123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528 |
- /*
- * $Id$
- *
- * resolver related functions
- *
- * Copyright (C) 2001-2003 FhG Fokus
- *
- * This file is part of ser, a free SIP server.
- *
- * ser is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * For a license to use the ser software under conditions
- * other than those described here, or to purchase support for this
- * software, please contact iptel.org by e-mail at the following addresses:
- * [email protected]
- *
- * ser is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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)
- */
- #ifndef __resolve_h
- #define __resolve_h
- #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"
- #include "dns_func.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 ANS_SIZE 8192
- #define DNS_HDR_SIZE 12
- #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;
- extern struct dns_func_t dns_func;
- /* query union*/
- union dns_query{
- HEADER hdr;
- unsigned char buff[MAX_QUERY_SIZE];
- };
- /* rdata struct*/
- struct rdata {
- unsigned short type;
- 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*/
- struct srv_rdata {
- unsigned short priority;
- unsigned short weight;
- unsigned short port;
- 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 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 {
- unsigned char ip[4];
- };
- struct aaaa_rdata {
- unsigned char ip6[16];
- };
- /* cname rec. struct*/
- struct cname_rdata {
- 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;
- };
- /* 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)
- #define HEX2I(c) \
- ( (((c)>='0') && ((c)<='9'))? (c)-'0' : \
- (((c)>='A') && ((c)<='F'))? ((c)-'A')+10 : \
- (((c)>='a') && ((c)<='f'))? ((c)-'a')+10 : -1 )
- /* converts a str to an ipv4 address, returns the address or 0 on error
- Warning: the result is a pointer to a statically allocated structure */
- static inline struct ip_addr* str2ip(str* st)
- {
- int i;
- unsigned char *limit;
- static struct ip_addr ip;
- unsigned char* s;
- s=(unsigned char*)st->s;
- /*init*/
- ip.u.addr32[0]=0;
- i=0;
- limit=(unsigned char*)(st->s + st->len);
- for(;s<limit ;s++){
- if (*s=='.'){
- i++;
- if (i>3) goto error_dots;
- }else if ( (*s <= '9' ) && (*s >= '0') ){
- ip.u.addr[i]=ip.u.addr[i]*10+*s-'0';
- }else{
- //error unknown char
- goto error_char;
- }
- }
- if (i<3) goto error_dots;
- ip.af=AF_INET;
- ip.len=4;
-
- return &ip;
- error_dots:
- #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;
- }
- /* 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)
- {
- int i, idx1, rest;
- int no_colons;
- int double_colon;
- int hex;
- static struct ip_addr ip;
- unsigned short* addr_start;
- unsigned short addr_end[8];
- unsigned short* addr;
- unsigned char* limit;
- unsigned char* s;
-
- /* init */
- 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;
- ip.af=AF_INET6;
- ip.len=16;
- addr_start=ip.u.addr16;
- addr=addr_start;
- memset(addr_start, 0 , 8*sizeof(unsigned short));
- memset(addr_end, 0 , 8*sizeof(unsigned short));
- for (; s<limit; s++){
- if (*s==':'){
- no_colons++;
- if (no_colons>7) goto error_too_many_colons;
- if (double_colon){
- idx1=i;
- i=0;
- if (addr==addr_end) goto error_colons;
- addr=addr_end;
- }else{
- double_colon=1;
- addr[i]=htons(addr[i]);
- i++;
- }
- }else if ((hex=HEX2I(*s))>=0){
- addr[i]=addr[i]*16+hex;
- double_colon=0;
- }else{
- /* error, unknown char */
- goto error_char;
- }
- }
- if (!double_colon){ /* not ending in ':' */
- addr[i]=htons(addr[i]);
- i++;
- }
- /* if address contained '::' fix it */
- 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",
- idx1, rest, no_colons, hex);
- DBG("str2ip6: address %x:%x:%x:%x:%x:%x:%x:%x\n",
- addr_start[0], addr_start[1], addr_start[2],
- addr_start[3], addr_start[4], addr_start[5],
- addr_start[6], addr_start[7] );
- */
- 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);*/
- return 0;
- }
- struct hostent* _sip_resolvehost(str* name, unsigned short* port, char* proto);
- /* gethostbyname wrapper, handles ip/ipv6 automatically */
- static inline struct hostent* _resolvehost(char* name)
- {
- static struct hostent* he=0;
- #ifdef HAVE_GETIPNODEBYNAME
- int err;
- static struct hostent* he2=0;
- #endif
- #ifndef DNS_IP_HACK
- int len;
- #endif
- #ifdef DNS_IP_HACK
- struct ip_addr* ip;
- str s;
- s.s = (char*)name;
- s.len = strlen(name);
- /* check if it's an ip address */
- if ( ((ip=str2ip(&s))!=0)
- || ((ip=str2ip6(&s))!=0)
- ){
- /* we are lucky, this is an ip address */
- return ip_addr2he(&s, ip);
- }
-
- #else /* DNS_IP_HACK */
- len=0;
- if (*name=='['){
- len=strlen(name);
- if (len && (name[len-1]==']')){
- name[len-1]=0; /* remove '[' */
- name++; /* skip '[' */
- goto skip_ipv4;
- }
- }
- #endif
- /* ipv4 */
- he=dns_func.sr_gethostbyname(name);
- if(he==0 && cfg_get(core, core_cfg, dns_try_ipv6)){
- #ifndef DNS_IP_HACK
- skip_ipv4:
- #endif
- /*try ipv6*/
- #ifdef HAVE_GETHOSTBYNAME2
- he=dns_func.sr_gethostbyname2(name, AF_INET6);
- #elif defined HAVE_GETIPNODEBYNAME
- /* on solaris 8 getipnodebyname has a memory leak,
- * after some time calls to it will fail with err=3
- * solution: patch your solaris 8 installation */
- if (he2) freehostent(he2);
- he=he2=getipnodebyname(name, AF_INET6, 0, &err);
- #else
- #error neither gethostbyname2 or getipnodebyname present
- #endif
- #ifndef DNS_IP_HACK
- if (len) name[len-2]=']'; /* restore */
- #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_proto_prefs(str *gname, str *name);
- struct dns_srv_proto {
- char proto;
- int proto_pref;
- };
- void create_srv_name(char proto, str *name, char *srv);
- size_t create_srv_pref_list(char *proto, struct dns_srv_proto *list);
- #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 */
- struct hostent* no_naptr_srv_sip_resolvehost(str* name, unsigned short* port,
- char* proto);
- #endif
|