- more dest_info conversions:
[sip-router] / resolve.c
1 /* $Id$*/
2 /*
3  *
4  * Copyright (C) 2001-2003 FhG Fokus
5  *
6  * This file is part of ser, a free SIP server.
7  *
8  * ser is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version
12  *
13  * For a license to use the ser software under conditions
14  * other than those described here, or to purchase support for this
15  * software, please contact iptel.org by e-mail at the following addresses:
16  *    info@iptel.org
17  *
18  * ser is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License 
24  * along with this program; if not, write to the Free Software 
25  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26  */
27 /*
28  * History:
29  * -------
30  *  2003-02-13  added proto to sip_resolvehost, for SRV lookups (andrei)
31  *  2003-07-03  default port value set according to proto (andrei)
32  *  2005-07-11  added resolv_init (timeouts a.s.o) (andrei)
33  *  2006-04-13  added sip_hostport2su()  (andrei)
34  */ 
35
36
37 #include <sys/types.h>
38 #include <netinet/in.h>
39 #include <arpa/nameser.h>
40 #include <resolv.h>
41 #include <string.h>
42
43 #include "resolve.h"
44 #include "dprint.h"
45 #include "mem/mem.h"
46 #include "ip_addr.h"
47 #include "error.h"
48
49
50
51 /* mallocs for local stuff */
52 #define local_malloc pkg_malloc
53 #define local_free   pkg_free
54
55 int dns_try_ipv6=1; /* default on */
56 /* declared in globals.h */
57 int dns_retr_time=-1;
58 int dns_retr_no=-1;
59 int dns_servers_no=-1;
60 int dns_search_list=-1;
61
62
63 /* init. the resolver
64  * params: retr_time  - time before retransmitting (must be >0)
65  *         retr_no    - retransmissions number
66  *         servers_no - how many dns servers will be used
67  *                      (from the one listed in /etc/resolv.conf)
68  *         search     - if 0 the search list in /etc/resolv.conf will
69  *                      be ignored (HINT: even if you don't have a
70  *                      search list in resolv.conf, it's still better
71  *                      to set search to 0, because an empty seachlist
72  *                      means in fact search "" => it takes more time)
73  * If any of the parameters <0, the default (system specific) value
74  * will be used. See also resolv.conf(5).
75  * returns: 0 on success, -1 on error
76  */
77 int resolv_init()
78 {
79         res_init();
80 #ifdef HAVE_RESOLV_RES
81         if (dns_retr_time>0)
82                 _res.retrans=dns_retr_time;
83         if (dns_retr_no>0)
84                 _res.retry=dns_retr_no;
85         if (dns_servers_no>=0)
86                 _res.nscount=dns_servers_no;
87         if (dns_search_list==0)
88                 _res.options&=~(RES_DEFNAMES|RES_DNSRCH);
89 #else
90 #warning "no resolv timeout support"
91         LOG(L_WARN, "WARNING: resolv_init: no resolv options support - resolv"
92                         " options will be ignored\n");
93 #endif
94         return 0;
95 }
96
97
98
99  /*  skips over a domain name in a dns message
100  *  (it can be  a sequence of labels ending in \0, a pointer or
101  *   a sequence of labels ending in a pointer -- see rfc1035
102  *   returns pointer after the domain name or null on error*/
103 unsigned char* dns_skipname(unsigned char* p, unsigned char* end)
104 {
105         while(p<end){
106                 /* check if \0 (root label length) */
107                 if (*p==0){
108                         p+=1;
109                         break;
110                 }
111                 /* check if we found a pointer */
112                 if (((*p)&0xc0)==0xc0){
113                         /* if pointer skip over it (2 bytes) & we found the end */
114                         p+=2;
115                         break;
116                 }
117                 /* normal label */
118                 p+=*p+1;
119         }
120         return (p>=end)?0:p;
121 }
122
123
124
125 /* parses the srv record into a srv_rdata structure
126  *   msg   - pointer to the dns message
127  *   end   - pointer to the end of the message
128  *   rdata - pointer  to the rdata part of the srv answer
129  * returns 0 on error, or a dyn. alloc'ed srv_rdata structure */
130 /* SRV rdata format:
131  *            111111
132  *  0123456789012345
133  * +----------------+
134  * |     priority   |
135  * |----------------|
136  * |     weight     |
137  * |----------------|
138  * |   port number  |
139  * |----------------|
140  * |                |
141  * ~      name      ~
142  * |                |
143  * +----------------+
144  */
145 struct srv_rdata* dns_srv_parser( unsigned char* msg, unsigned char* end,
146                                                                   unsigned char* rdata)
147 {
148         struct srv_rdata* srv;
149         int len;
150         
151         srv=0;
152         if ((rdata+6)>=end) goto error;
153         srv=(struct srv_rdata*)local_malloc(sizeof(struct srv_rdata));
154         if (srv==0){
155                 LOG(L_ERR, "ERROR: dns_srv_parser: out of memory\n");
156                 goto error;
157         }
158         
159         memcpy((void*)&srv->priority, rdata, 2);
160         memcpy((void*)&srv->weight,   rdata+2, 2);
161         memcpy((void*)&srv->port,     rdata+4, 2);
162         rdata+=6;
163         srv->priority=ntohs(srv->priority);
164         srv->weight=ntohs(srv->weight);
165         srv->port=ntohs(srv->port);
166         if ((len=dn_expand(msg, end, rdata, srv->name, MAX_DNS_NAME-1))==-1)
167                 goto error;
168         /* add terminating 0 ? (warning: len=compressed name len) */
169         return srv;
170 error:
171         if (srv) local_free(srv);
172         return 0;
173 }
174
175
176 /* parses the naptr record into a naptr_rdata structure
177  *   msg   - pointer to the dns message
178  *   end   - pointer to the end of the message
179  *   rdata - pointer  to the rdata part of the naptr answer
180  * returns 0 on error, or a dyn. alloc'ed naptr_rdata structure */
181 /* NAPTR rdata format:
182  *            111111
183  *  0123456789012345
184  * +----------------+
185  * |      order     |
186  * |----------------|
187  * |   preference   |
188  * |----------------|
189  * ~     flags      ~
190  * |   (string)     |
191  * |----------------|
192  * ~    services    ~
193  * |   (string)     |
194  * |----------------|
195  * ~    regexp      ~
196  * |   (string)     |
197  * |----------------|
198  * ~  replacement   ~
199    |    (name)      |
200  * +----------------+
201  */
202 struct naptr_rdata* dns_naptr_parser( unsigned char* msg, unsigned char* end,
203                                                                   unsigned char* rdata)
204 {
205         struct naptr_rdata* naptr;
206         int len;
207         
208         naptr = 0;
209         if ((rdata + 7) >= end) goto error;
210         naptr=(struct naptr_rdata*)local_malloc(sizeof(struct naptr_rdata));
211         if (naptr == 0){
212                 LOG(L_ERR, "ERROR: dns_naptr_parser: out of memory\n");
213                 goto error;
214         }
215         
216         memcpy((void*)&naptr->order, rdata, 2);
217         naptr->order=ntohs(naptr->order);
218         memcpy((void*)&naptr->pref, rdata + 2, 2);
219         naptr->pref=ntohs(naptr->pref);
220         naptr->flags_len = (int)rdata[4];
221         if ((rdata + 7 +  naptr->flags_len) >= end) goto error;
222         memcpy((void*)&naptr->flags, rdata + 5, naptr->flags_len);
223         naptr->services_len = (int)rdata[5 + naptr->flags_len];
224         if ((rdata + 7 + naptr->flags_len + naptr->services_len) >= end) goto error;
225         memcpy((void*)&naptr->services, rdata + 6 + naptr->flags_len, naptr->services_len);
226         naptr->regexp_len = (int)rdata[6 + naptr->flags_len + naptr->services_len];
227         if ((rdata + 7 + naptr->flags_len + naptr->services_len +
228                                         naptr->regexp_len) >= end) goto error;
229         memcpy((void*)&naptr->regexp, rdata + 7 + naptr->flags_len +
230                                 naptr->services_len, naptr->regexp_len);
231         rdata = rdata + 7 + naptr->flags_len + naptr->services_len + 
232                         naptr->regexp_len;
233         if ((len=dn_expand(msg, end, rdata, naptr->repl, MAX_DNS_NAME-1)) == -1)
234                 goto error;
235         /* add terminating 0 ? (warning: len=compressed name len) */
236         return naptr;
237 error:
238         if (naptr) local_free(naptr);
239         return 0;
240 }
241
242
243
244 /* parses a CNAME record into a cname_rdata structure */
245 struct cname_rdata* dns_cname_parser( unsigned char* msg, unsigned char* end,
246                                                                           unsigned char* rdata)
247 {
248         struct cname_rdata* cname;
249         int len;
250         
251         cname=0;
252         cname=(struct cname_rdata*)local_malloc(sizeof(struct cname_rdata));
253         if(cname==0){
254                 LOG(L_ERR, "ERROR: dns_cname_parser: out of memory\n");
255                 goto error;
256         }
257         if ((len=dn_expand(msg, end, rdata, cname->name, MAX_DNS_NAME-1))==-1)
258                 goto error;
259         return cname;
260 error:
261         if (cname) local_free(cname);
262         return 0;
263 }
264
265
266
267 /* parses an A record rdata into an a_rdata structure
268  * returns 0 on error or a dyn. alloc'ed a_rdata struct
269  */
270 struct a_rdata* dns_a_parser(unsigned char* rdata, unsigned char* end)
271 {
272         struct a_rdata* a;
273         
274         if (rdata+4>=end) goto error;
275         a=(struct a_rdata*)local_malloc(sizeof(struct a_rdata));
276         if (a==0){
277                 LOG(L_ERR, "ERROR: dns_a_parser: out of memory\n");
278                 goto error;
279         }
280         memcpy(a->ip, rdata, 4);
281         return a;
282 error:
283         return 0;
284 }
285
286
287
288 /* parses an AAAA (ipv6) record rdata into an aaaa_rdata structure
289  * returns 0 on error or a dyn. alloc'ed aaaa_rdata struct */
290 struct aaaa_rdata* dns_aaaa_parser(unsigned char* rdata, unsigned char* end)
291 {
292         struct aaaa_rdata* aaaa;
293         
294         if (rdata+16>=end) goto error;
295         aaaa=(struct aaaa_rdata*)local_malloc(sizeof(struct aaaa_rdata));
296         if (aaaa==0){
297                 LOG(L_ERR, "ERROR: dns_aaaa_parser: out of memory\n");
298                 goto error;
299         }
300         memcpy(aaaa->ip6, rdata, 16);
301         return aaaa;
302 error:
303         return 0;
304 }
305
306
307
308 /* frees completely a struct rdata list */
309 void free_rdata_list(struct rdata* head)
310 {
311         struct rdata* l;
312         for(l=head; l; l=l->next){
313                 /* free the parsed rdata*/
314                 if (l->rdata) local_free(l->rdata);
315                 local_free(l);
316         }
317 }
318
319
320
321 /* gets the DNS records for name:type
322  * returns a dyn. alloc'ed struct rdata linked list with the parsed responses
323  * or 0 on error
324  * see rfc1035 for the query/response format */
325 struct rdata* get_record(char* name, int type)
326 {
327         int size;
328         int qno, answers_no;
329         int r;
330         int ans_len;
331         static union dns_query buff;
332         unsigned char* p;
333         unsigned char* t;
334         unsigned char* end;
335         static unsigned char answer[ANS_SIZE];
336         unsigned short rtype, class, rdlength;
337         unsigned int ttl;
338         struct rdata* head;
339         struct rdata** crt;
340         struct rdata** last;
341         struct rdata* rd;
342         struct srv_rdata* srv_rd;
343         struct srv_rdata* crt_srv;
344         
345         size=res_search(name, C_IN, type, buff.buff, sizeof(buff));
346         if (size<0) {
347                 DBG("get_record: lookup(%s, %d) failed\n", name, type);
348                 goto not_found;
349         }
350         else if (size > sizeof(buff)) size=sizeof(buff);
351         head=rd=0;
352         last=crt=&head;
353         
354         p=buff.buff+DNS_HDR_SIZE;
355         end=buff.buff+size;
356         if (p>=end) goto error_boundary;
357         qno=ntohs((unsigned short)buff.hdr.qdcount);
358
359         for (r=0; r<qno; r++){
360                 /* skip the name of the question */
361                 if ((p=dns_skipname(p, end))==0) {
362                         LOG(L_ERR, "ERROR: get_record: skipname==0\n");
363                         goto error;
364                 }
365                 p+=2+2; /* skip QCODE & QCLASS */
366         #if 0
367                 for (;(p<end && (*p)); p++);
368                 p+=1+2+2; /* skip the ending  '\0, QCODE and QCLASS */
369         #endif
370                 if (p>=end) {
371                         LOG(L_ERR, "ERROR: get_record: p>=end\n");
372                         goto error;
373                 }
374         };
375         answers_no=ntohs((unsigned short)buff.hdr.ancount);
376         ans_len=ANS_SIZE;
377         t=answer;
378         for (r=0; (r<answers_no) && (p<end); r++){
379                 /*  ignore it the default domain name */
380                 if ((p=dns_skipname(p, end))==0) {
381                         LOG(L_ERR, "ERROR: get_record: skip_name=0 (#2)\n");
382                         goto error;
383                 }
384                 /*
385                 skip=dn_expand(buff.buff, end, p, t, ans_len);
386                 p+=skip;
387                 */
388                 /* check if enough space is left for type, class, ttl & size */
389                 if ((p+2+2+4+2)>=end) goto error_boundary;
390                 /* get type */
391                 memcpy((void*) &rtype, (void*)p, 2);
392                 rtype=ntohs(rtype);
393                 p+=2;
394                 /* get  class */
395                 memcpy((void*) &class, (void*)p, 2);
396                 class=ntohs(class);
397                 p+=2;
398                 /* get ttl*/
399                 memcpy((void*) &ttl, (void*)p, 4);
400                 ttl=ntohl(ttl);
401                 p+=4;
402                 /* get size */
403                 memcpy((void*)&rdlength, (void*)p, 2);
404                 rdlength=ntohs(rdlength);
405                 p+=2;
406                 /* check for type */
407                 /*
408                 if (rtype!=type){
409                         LOG(L_ERR, "WARNING: get_record: wrong type in answer (%d!=%d)\n",
410                                         rtype, type);
411                         p+=rdlength;
412                         continue;
413                 }
414                 */
415                 /* expand the "type" record  (rdata)*/
416                 
417                 rd=(struct rdata*) local_malloc(sizeof(struct rdata));
418                 if (rd==0){
419                         LOG(L_ERR, "ERROR: get_record: out of memory\n");
420                         goto error;
421                 }
422                 rd->type=rtype;
423                 rd->class=class;
424                 rd->ttl=ttl;
425                 rd->next=0;
426                 switch(rtype){
427                         case T_SRV:
428                                 srv_rd= dns_srv_parser(buff.buff, end, p);
429                                 rd->rdata=(void*)srv_rd;
430                                 if (srv_rd==0) goto error_parse;
431                                 
432                                 /* insert sorted into the list */
433                                 for (crt=&head; *crt; crt= &((*crt)->next)){
434                                         crt_srv=(struct srv_rdata*)(*crt)->rdata;
435                                         if ((srv_rd->priority <  crt_srv->priority) ||
436                                            ( (srv_rd->priority == crt_srv->priority) && 
437                                                          (srv_rd->weight > crt_srv->weight) ) ){
438                                                 /* insert here */
439                                                 goto skip;
440                                         }
441                                 }
442                                 last=&(rd->next); /*end of for => this will be the last elem*/
443                         skip:
444                                 /* insert here */
445                                 rd->next=*crt;
446                                 *crt=rd;
447                                 
448                                 break;
449                         case T_A:
450                                 rd->rdata=(void*) dns_a_parser(p,end);
451                                 if (rd->rdata==0) goto error_parse;
452                                 *last=rd; /* last points to the last "next" or the list head*/
453                                 last=&(rd->next);
454                                 break;
455                         case T_AAAA:
456                                 rd->rdata=(void*) dns_aaaa_parser(p,end);
457                                 if (rd->rdata==0) goto error_parse;
458                                 *last=rd;
459                                 last=&(rd->next);
460                                 break;
461                         case T_CNAME:
462                                 rd->rdata=(void*) dns_cname_parser(buff.buff, end, p);
463                                 if(rd->rdata==0) goto error_parse;
464                                 *last=rd;
465                                 last=&(rd->next);
466                                 break;
467                         case T_NAPTR:
468                                 rd->rdata=(void*) dns_naptr_parser(buff.buff, end, p);
469                                 if(rd->rdata==0) goto error_parse;
470                                 *last=rd;
471                                 last=&(rd->next);
472                                 break;
473                         default:
474                                 LOG(L_ERR, "WARNING: get_record: unknown type %d\n", rtype);
475                                 rd->rdata=0;
476                                 *last=rd;
477                                 last=&(rd->next);
478                 }
479                 
480                 p+=rdlength;
481                 
482         }
483         return head;
484 error_boundary:
485                 LOG(L_ERR, "ERROR: get_record: end of query buff reached\n");
486                 return 0;
487 error_parse:
488                 LOG(L_ERR, "ERROR: get_record: rdata parse error \n");
489                 if (rd) local_free(rd); /* rd->rdata=0 & rd is not linked yet into
490                                                                    the list */
491 error:
492                 LOG(L_ERR, "ERROR: get_record \n");
493                 if (head) free_rdata_list(head);
494 not_found:
495         return 0;
496 }
497
498
499
500 /* resolves a host name trying SRV lookup if *port==0 or normal A/AAAA lookup
501  * if *port!=0.
502  * when performing SRV lookup (*port==0) it will use proto to look for
503  * tcp or udp hosts, otherwise proto is unused; if proto==0 => no SRV lookup
504  * returns: hostent struct & *port filled with the port from the SRV record;
505  *  0 on error
506  */
507 struct hostent* sip_resolvehost(str* name, unsigned short* port, int proto)
508 {
509         struct hostent* he;
510         struct rdata* head;
511         struct rdata* l;
512         struct srv_rdata* srv;
513         struct ip_addr* ip;
514         static char tmp[MAX_DNS_NAME]; /* tmp. buff. for SRV lookups */
515
516         /* try SRV if no port specified (draft-ietf-sip-srv-06) */
517         if ((port)&&(*port==0)){
518                 *port=(proto==PROTO_TLS)?SIPS_PORT:SIP_PORT; /* just in case we don't
519                                                                                                                 find another */
520                 if ((name->len+SRV_MAX_PREFIX_LEN+1)>MAX_DNS_NAME){
521                         LOG(L_WARN, "WARNING: sip_resolvehost: domain name too long (%d),"
522                                                 " unable to perform SRV lookup\n", name->len);
523                 }else{
524                         /* check if it's an ip address */
525                         if ( ((ip=str2ip(name))!=0)
526 #ifdef  USE_IPV6
527                                   || ((ip=str2ip6(name))!=0)
528 #endif
529                                 ){
530                                 /* we are lucky, this is an ip address */
531                                 return ip_addr2he(name,ip);
532                         }
533                         
534                         switch(proto){
535                                 case PROTO_NONE: /* no proto specified, use udp */
536                                         goto skip_srv;
537                                 case PROTO_UDP:
538                                         memcpy(tmp, SRV_UDP_PREFIX, SRV_UDP_PREFIX_LEN);
539                                         memcpy(tmp+SRV_UDP_PREFIX_LEN, name->s, name->len);
540                                         tmp[SRV_UDP_PREFIX_LEN + name->len] = '\0';
541                                         break;
542                                 case PROTO_TCP:
543                                         memcpy(tmp, SRV_TCP_PREFIX, SRV_TCP_PREFIX_LEN);
544                                         memcpy(tmp+SRV_TCP_PREFIX_LEN, name->s, name->len);
545                                         tmp[SRV_TCP_PREFIX_LEN + name->len] = '\0';
546                                         break;
547                                 case PROTO_TLS:
548                                         memcpy(tmp, SRV_TLS_PREFIX, SRV_TLS_PREFIX_LEN);
549                                         memcpy(tmp+SRV_TLS_PREFIX_LEN, name->s, name->len);
550                                         tmp[SRV_TLS_PREFIX_LEN + name->len] = '\0';
551                                         break;
552                                 default:
553                                         LOG(L_CRIT, "BUG: sip_resolvehost: unknown proto %d\n",
554                                                         proto);
555                                         return 0;
556                         }
557
558                         head=get_record(tmp, T_SRV);
559                         for(l=head; l; l=l->next){
560                                 if (l->type!=T_SRV) continue; /*should never happen*/
561                                 srv=(struct srv_rdata*) l->rdata;
562                                 if (srv==0){
563                                         LOG(L_CRIT, "sip_resolvehost: BUG: null rdata\n");
564                                         free_rdata_list(head);
565                                         break;
566                                 }
567                                 he=resolvehost(srv->name);
568                                 if (he!=0){
569                                         /* we found it*/
570                                         DBG("sip_resolvehost: SRV(%s) = %s:%d\n",
571                                                         tmp, srv->name, srv->port);
572                                         *port=srv->port;
573                                         free_rdata_list(head); /*clean up*/
574                                         return he;
575                                 }
576                         }
577                         if (head) free_rdata_list(head); /*clean up*/
578                         DBG("sip_resolvehost: no SRV record found for %.*s," 
579                                         " trying 'normal' lookup...\n", name->len, name->s);
580                 }
581         }
582 skip_srv:
583         if (name->len >= MAX_DNS_NAME) {
584                 LOG(L_ERR, "sip_resolvehost: domain name too long\n");
585                 return 0;
586         }
587         memcpy(tmp, name->s, name->len);
588         tmp[name->len] = '\0';
589         he=resolvehost(tmp);
590         return he;
591 }
592
593
594
595 /* resolve host, port, proto using sip rules (e.g. use SRV if port=0 a.s.o)
596  *  and write the result in the sockaddr_union to
597  *  returns -1 on error (resolve failed), 0 on success */
598 int sip_hostport2su(union sockaddr_union* su, str* name, unsigned short port,
599                                                 int proto)
600 {
601         struct hostent* he;
602         
603         
604         he=sip_resolvehost(name, &port, proto);
605         if (he==0){
606                 ser_error=E_BAD_ADDRESS;
607                 LOG(L_ERR, "ERROR: sip_hostport2su: could not resolve hostname:"
608                                         " \"%.*s\"\n", name->len, name->s);
609                 goto error;
610         }
611         /* port filled by sip_resolvehost if empty*/
612         if (hostent2su(su, he, 0, port)<0){
613                 ser_error=E_BAD_ADDRESS;
614                 goto error;
615         }
616         return 0;
617 error:
618         return -1;
619 }