pkg/kamailio/fedora/16: Updated rel in .spec to dev2
[sip-router] / resolve.h
index 9285bb0..8ce68e6 100644 (file)
--- a/resolve.h
+++ b/resolve.h
@@ -3,7 +3,7 @@
  *
  * resolver related functions
  *
- * Copyright (C) 2001-2003 Fhg Fokus
+ * Copyright (C) 2001-2003 FhG Fokus
  *
  * This file is part of ser, a free SIP server.
  *
  * along with this program; if not, write to the Free Software 
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
+/* History:
+ * --------
+ *  2003-04-12  support for resolving ipv6 address references added (andrei)
+ *  2004-07-28  darwin needs nameser_compat.h (andrei)
+ *  2006-07-13  rdata structures put on diet (andrei)
+ *  2006-07-17  rdata contains now also the record name (andrei)
+ *  2006-08-18  get_record uses flags (andrei)
+ *  2006-06-16  naptr support (andrei)
+ */
 
 
 
 
 #include <sys/types.h>
 #include <sys/socket.h>
+#include <netinet/in.h>
 #include <netdb.h>
 #include <arpa/nameser.h>
+#include <resolv.h>
+#include "counters.h"
+
+#ifdef __OS_darwin
+#include <arpa/nameser_compat.h>
+#endif
 
 #include "ip_addr.h"
+#ifdef USE_DNS_CACHE
+#include "dns_wrappers.h"
+#endif
+
+/* define RESOLVE_DBG for debugging info (very noisy) */
+#define RESOLVE_DBG
+/* define NAPTR_DBG for naptr related debugging info (very noisy) */
+#define NAPTR_DBG
 
 
 #define MAX_QUERY_SIZE 8192
 #define MAX_DNS_NAME 256
 #define MAX_DNS_STRING 255
 
+#ifndef T_EBL
+/** not official yet - iEnum. */
+#define T_EBL 65300
+#endif
+
+/* get_record flags */
+#define RES_ONLY_TYPE 1   /* return only the specified type records */
+#define RES_AR           2   /* return also the additional records */
+
+/* counter for failed DNS requests
+*/
+struct dns_counters_h {
+    counter_handle_t failed_dns_req;
+};
 
+extern struct dns_counters_h dns_cnts_h;
 
 /* query union*/
 union dns_query{
@@ -58,11 +97,15 @@ union dns_query{
 /* rdata struct*/
 struct rdata {
        unsigned short type;
-       unsigned short class;
+       unsigned short pclass;
        unsigned int   ttl;
        void* rdata;
        struct rdata* next;
+       unsigned char name_len; /* name length w/o the terminating 0 */
+       char name[1]; /* null terminated name (len=name_len+1) */
 };
+/* real size of the structure */
+#define RDATA_SIZE(s) (sizeof(struct rdata)+(s).name_len) /* +1-1 */
 
 
 /* srv rec. struct*/
@@ -70,24 +113,39 @@ struct srv_rdata {
        unsigned short priority;
        unsigned short weight;
        unsigned short port;
-       unsigned int name_len;
-       char name[MAX_DNS_NAME];
+       unsigned char name_len; /* name length w/o the terminating 0 */
+       char name[1]; /* null terminated name (len=name_len+1) */
 };
 
+
+/* real size of the structure */
+#define SRV_RDATA_SIZE(s) (sizeof(struct srv_rdata)+(s).name_len)
+
 /* naptr rec. struct*/
 struct naptr_rdata {
+       char* flags;    /* points inside str_table */
+       char* services; /* points inside str_table */
+       char* regexp;   /* points inside str_table */
+       char* repl;     /* points inside str_table, null terminated */
+       
        unsigned short order;
        unsigned short pref;
-       unsigned int flags_len;
-       char flags[MAX_DNS_STRING];
-       unsigned int services_len;
-       char services[MAX_DNS_STRING];
-       unsigned int regexp_len;
-       char regexp[MAX_DNS_STRING];
-       unsigned int repl_len; /* not currently used */
-       char repl[MAX_DNS_NAME];
+       
+       unsigned char flags_len;
+       unsigned char services_len;
+       unsigned char regexp_len;
+       unsigned char repl_len; /* not currently used */
+       
+       char str_table[1]; /* contains all the strings */
 };
 
+/* real size of the structure */
+#define NAPTR_RDATA_SIZE(s) (sizeof(struct naptr_rdata) \
+                                                               + (s).flags_len \
+                                                               + (s).services_len \
+                                                               + (s).regexp_len \
+                                                               + (s).repl_len + 1 - 1)
+
 
 /* A rec. struct */
 struct a_rdata {
@@ -100,19 +158,63 @@ struct aaaa_rdata {
 
 /* cname rec. struct*/
 struct cname_rdata {
-       char name[MAX_DNS_NAME];
+       unsigned char name_len; /* name length w/o the terminating 0 */
+       char name[1]; /* null terminated name (len=name_len+1) */
 };
 
+/* real size of the structure */
+#define CNAME_RDATA_SIZE(s) (sizeof(struct cname_rdata)+(s).name_len)
 
+/* dns character-string */
+struct dns_cstr{
+       char* cstr; /* pointer to null term. string */
+       unsigned char cstr_len;
+};
 
-struct rdata* get_record(char* name, int type);
-void free_rdata_list(struct rdata* head);
+/* txt rec. struct */
+struct txt_rdata {
+       unsigned short cstr_no; /* number of strings */
+       unsigned short tslen; /* total strings table len */
+       struct dns_cstr txt[1]; /* at least 1 */
+       /* all txt[*].cstr point inside a string table at the end of the struct.*/
+};
+
+#define TXT_RDATA_SIZE(s) \
+       (sizeof(struct txt_rdata)+((s).cstr_no-1)*sizeof(struct dns_cstr)+\
+               (s).tslen)
+
+/* ebl rec. struct, see
+   http://tools.ietf.org/html/draft-ietf-enum-branch-location-record-03 */
+struct ebl_rdata {
+       char* separator; /* points inside str_table */
+       char* apex;      /* point inside str_table */
+       unsigned char separator_len; /* separator len w/o the terminating 0 */
+       unsigned char apex_len;      /* apex len w/p the terminating 0 */
+       unsigned char position;
+       char str_table[1]; /* contains the 2 strings: separator and apex */
+};
+#define EBL_RDATA_SIZE(s) \
+       (sizeof(struct ebl_rdata)-1+(s).separator_len+1+(s).apex_len+1)
+
+
+struct ptr_rdata {
+       unsigned char ptrdname_len; /* name length w/o the terminating 0 */
+       char ptrdname[1]; /* null terminated name (len=name_len+1) */
+};
+/* real size of the structure */
+#define PTR_RDATA_SIZE(s) (sizeof(struct ptr_rdata)-1+(s).ptrdname_len+1)
 
 
+#ifdef HAVE_RESOLV_RES
+int match_search_list(const struct __res_state* res, char* name);
+#endif
+struct rdata* get_record(char* name, int type, int flags);
+void free_rdata_list(struct rdata* head);
+
 
 
 #define rev_resolvehost(ip)\
-                                       gethostbyaddr((char*)(ip)->u.addr, (ip)->len, (ip)->af);
+                                       gethostbyaddr((char*)(ip)->u.addr, (ip)->len, (ip)->af)
 
 
 
@@ -152,25 +254,26 @@ static inline struct ip_addr* str2ip(str* st)
                                goto error_char;
                }
        }
+       if (i<3) goto error_dots;
        ip.af=AF_INET;
        ip.len=4;
        
        return &ip;
-
-
-            /* FIXME: janakj - is this correct ?, we return always 0 here 
-             * Also we could use different loglevels here
-             */
 error_dots:
-       DBG("str2ip: ERROR: too many dots in [%.*s]\n", st->len, st->s);
+#ifdef RESOLVE_DBG
+       DBG("str2ip: ERROR: too %s dots in [%.*s]\n", (i>3)?"many":"few", 
+                       st->len, st->s);
+#endif
        return 0;
  error_char:
+       /*
        DBG("str2ip: WARNING: unexpected char %c in [%.*s]\n", *s, st->len, st->s);
+       */
        return 0;
 }
 
 
-
+#ifdef USE_IPV6
 /* returns an ip_addr struct.; on error returns 0
  * the ip_addr struct is static, so subsequent calls will destroy its content*/
 static inline struct ip_addr* str2ip6(str* st)
@@ -187,7 +290,15 @@ static inline struct ip_addr* str2ip6(str* st)
        unsigned char* s;
        
        /* init */
-       s=(unsigned char*)st->s;
+       if ((st->len) && (st->s[0]=='[')){
+               /* skip over [ ] */
+               if (st->s[st->len-1]!=']') goto error_char;
+               s=(unsigned char*)(st->s+1);
+               limit=(unsigned char*)(st->s+st->len-1);
+       }else{
+               s=(unsigned char*)st->s;
+               limit=(unsigned char*)(st->s+st->len);
+       }
        i=idx1=rest=0;
        double_colon=0;
        no_colons=0;
@@ -195,7 +306,6 @@ static inline struct ip_addr* str2ip6(str* st)
        ip.len=16;
        addr_start=ip.u.addr16;
        addr=addr_start;
-       limit=(unsigned char*)(st->s+st->len);
        memset(addr_start, 0 , 8*sizeof(unsigned short));
        memset(addr_end, 0 , 8*sizeof(unsigned short));
        for (; s<limit; s++){
@@ -220,7 +330,6 @@ static inline struct ip_addr* str2ip6(str* st)
                        goto error_char;
                }
        }
-       if (no_colons<2) goto error_too_few_colons;
        if (!double_colon){ /* not ending in ':' */
                addr[i]=htons(addr[i]);
                i++; 
@@ -229,6 +338,9 @@ static inline struct ip_addr* str2ip6(str* st)
        if (addr==addr_end){
                rest=8-i-idx1;
                memcpy(addr_start+idx1+rest, addr_end, i*sizeof(unsigned short));
+       }else{
+               /* no double colons inside */
+               if (no_colons<7) goto error_too_few_colons;
        }
 /*
        DBG("str2ip6: idx1=%d, rest=%d, no_colons=%d, hex=%x\n",
@@ -241,39 +353,52 @@ static inline struct ip_addr* str2ip6(str* st)
        return &ip;
 
 error_too_many_colons:
+#ifdef RESOLVE_DBG
        DBG("str2ip6: ERROR: too many colons in [%.*s]\n", st->len, st->s);
+#endif
        return 0;
 
 error_too_few_colons:
+#ifdef RESOLVE_DBG
        DBG("str2ip6: ERROR: too few colons in [%.*s]\n", st->len, st->s);
+#endif
        return 0;
 
 error_colons:
+#ifdef RESOLVE_DBG
        DBG("str2ip6: ERROR: too many double colons in [%.*s]\n", st->len, st->s);
+#endif
        return 0;
 
 error_char:
+       /*
        DBG("str2ip6: WARNING: unexpected char %c in  [%.*s]\n", *s, st->len,
-                       st->s);
+                       st->s);*/
        return 0;
 }
+#endif /* USE_IPV6 */
 
 
 
-struct hostent* sip_resolvehost(str* name, unsigned short* port, int proto);
-
+struct hostent* _sip_resolvehost(str* name, unsigned short* port, char* proto);
 
 
-/* gethostbyname wrappers
- * use this, someday they will use a local cache */
 
-static inline struct hostent* resolvehost(const char* name)
+/* gethostbyname wrapper, handles ip/ipv6 automatically */
+static inline struct hostent* _resolvehost(char* name)
 {
        static struct hostent* he=0;
 #ifdef HAVE_GETIPNODEBYNAME 
+#ifdef USE_IPV6
        int err;
        static struct hostent* he2=0;
 #endif
+#endif
+#ifndef DNS_IP_HACK
+#ifdef USE_IPV6
+       int len;
+#endif
+#endif
 #ifdef DNS_IP_HACK
        struct ip_addr* ip;
        str s;
@@ -291,11 +416,26 @@ static inline struct hostent* resolvehost(const char* name)
                return ip_addr2he(&s, ip);
        }
        
+#else /* DNS_IP_HACK */
+#ifdef USE_IPV6
+       len=0;
+       if (*name=='['){
+               len=strlen(name);
+               if (len && (name[len-1]==']')){
+                       name[len-1]=0; /* remove '[' */
+                       name++; /* skip '[' */
+                       goto skip_ipv4;
+               }
+       }
+#endif
 #endif
        /* ipv4 */
        he=gethostbyname(name);
 #ifdef USE_IPV6
-       if(he==0){
+       if(he==0 && cfg_get(core, core_cfg, dns_try_ipv6)){
+#ifndef DNS_IP_HACK
+skip_ipv4:
+#endif
                /*try ipv6*/
        #ifdef HAVE_GETHOSTBYNAME2
                he=gethostbyname2(name, AF_INET6);
@@ -308,11 +448,79 @@ static inline struct hostent* resolvehost(const char* name)
        #else
                #error neither gethostbyname2 or getipnodebyname present
        #endif
+#ifndef DNS_IP_HACK
+               if (len) name[len-2]=']'; /* restore */
+#endif
        }
 #endif
        return he;
 }
 
 
+int resolv_init(void);
+
+/* callback/fixup functions executed by the configuration framework */
+void resolv_reinit(str *gname, str *name);
+int dns_reinit_fixup(void *handle, str *gname, str *name, void **val);
+int dns_try_ipv6_fixup(void *handle, str *gname, str *name, void **val);
+void reinit_naptr_proto_prefs(str *gname, str *name);
+
+#ifdef DNS_WATCHDOG_SUPPORT
+/* callback function that is called by the child processes
+ * when they reinitialize the resolver
+ *
+ * Note, that this callback is called by each chiled process separately!!!
+ * If the callback is registered after forking, only the child process
+ * that installs the hook will call the callback.
+ */
+typedef void (*on_resolv_reinit)(str*);
+int register_resolv_reinit_cb(on_resolv_reinit cb);
+#endif
+
+
+int sip_hostport2su(union sockaddr_union* su, str* host, unsigned short port,
+                                               char* proto);
+
+
+
+/* wrappers */
+#ifdef USE_DNS_CACHE
+#define resolvehost dns_resolvehost
+#define sip_resolvehost dns_sip_resolvehost
+#else
+#define resolvehost _resolvehost
+#define sip_resolvehost _sip_resolvehost
+#endif
+
+
+
+#ifdef USE_NAPTR
+/* NAPTR helper functions */
+typedef unsigned int naptr_bmp_t; /* type used for keeping track of tried
+                                                                        naptr records*/
+#define MAX_NAPTR_RRS (sizeof(naptr_bmp_t)*8)
+
+/* use before first call to naptr_sip_iterate */
+#define naptr_iterate_init(bmp) \
+       do{ \
+               *(bmp)=0; \
+       }while(0) \
+
+struct rdata* naptr_sip_iterate(struct rdata* naptr_head, 
+                                                                               naptr_bmp_t* tried,
+                                                                               str* srv_name, char* proto);
+/* returns sip proto if valis sip naptr record, .-1 otherwise */
+char naptr_get_sip_proto(struct naptr_rdata* n);
+/* returns true if new_proto is preferred over old_proto */
+int naptr_proto_preferred(char new_proto, char old_proto);
+/* returns true if we support the protocol */
+int naptr_proto_supported(char proto);
+/* choose between 2 naptr records, should take into account local
+ * preferences too
+ * returns 1 if the new record was selected, 0 otherwise */
+int naptr_choose (struct naptr_rdata** crt, char* crt_proto,
+                                                                       struct naptr_rdata* n , char n_proto);
+
+#endif/* USE_NAPTR */
 
 #endif