/* iterates over a naptr rr list, returning each time a "good" naptr record * is found.( srv type, no regex and a supported protocol) * params: * naptr_head - naptr rr list head * tried - bitmap used to keep track of the already tried records * (no more then sizeof(tried)*8 valid records are * ever walked * srv_name - if succesfull, it will be set to the selected record * srv name (naptr repl.) * proto - if succesfull it will be set to the selected record * protocol * returns 0 if no more records found or a pointer to the selected record * and sets protocol and srv_name * WARNING: when calling first time make sure you run first * naptr_iterate_init(&tried) */ struct rdata* naptr_sip_iterate(struct rdata* naptr_head, naptr_bmp_t* tried, str* srv_name, char* proto) { int i, idx; struct rdata* l; struct rdata* l_saved; struct naptr_rdata* naptr; struct naptr_rdata* naptr_saved; char saved_proto; char naptr_proto; idx=0; naptr_proto=PROTO_NONE; naptr_saved=0; l_saved=0; saved_proto=0; i=0; for(l=naptr_head; l && (i<MAX_NAPTR_RRS); l=l->next){ if (l->type!=T_NAPTR) continue; naptr=(struct naptr_rdata*) l->rdata; if (naptr==0){ LOG(L_CRIT, "naptr_iterate: BUG: null rdata\n"); goto end; } /* check if valid and get proto */ if ((naptr_proto=naptr_get_sip_proto(naptr))<=0) continue; if (*tried& (1<<i)){ i++; continue; /* already tried */ } #ifdef NAPTR_DBG DBG("naptr_iterate: found a valid sip NAPTR rr %.*s," " proto %d\n", naptr->repl_len, naptr->repl, (int)naptr_proto); #endif if ((naptr_proto_supported(naptr_proto))){ if (naptr_choose(&naptr_saved, &saved_proto, naptr, naptr_proto)) idx=i; l_saved=l; } i++; } if (naptr_saved){ /* found something */ #ifdef NAPTR_DBG DBG("naptr_iterate: choosed NAPTR rr %.*s, proto %d" " tried: 0x%x\n", naptr_saved->repl_len, naptr_saved->repl, (int)saved_proto, *tried); #endif *tried|=1<<idx; *proto=saved_proto; srv_name->s=naptr_saved->repl; srv_name->len=naptr_saved->repl_len; return l_saved; } end: return 0; }
size_t create_srv_pref_list(char *proto, struct dns_srv_proto *list) { struct dns_srv_proto tmp; size_t i,j,list_len; int default_order,max; /* if proto available, then add only the forced protocol to the list */ if (proto && *proto!=PROTO_NONE){ list[0].proto=*proto; list_len=1; } else { list_len = 0; /*get protocols and preference scores, and add availble protocol(s) and score(s) to the list*/ for (i=PROTO_UDP; i<PROTO_LAST;i++) { tmp.proto_pref = srv_proto_pref_score(i); /* if -1 so disabled continue with next protocol*/ if (naptr_proto_supported(i) == 0) { continue; } else { list[i-1].proto_pref=tmp.proto_pref; list[i-1].proto=i; list_len++; } }; /* if all protocol prefence scores equal, then set the perference to default values: udp,tcp,tls,sctp */ for (i=1; i<list_len;i++) { if(list[0].proto_pref!=list[i].proto_pref){ default_order=0; } } if (default_order){ for (i=0; i<list_len;i++) { list[i].proto_pref=srv_proto_pref_score(i); } } /* sorting the list */ for (i=0;i<list_len-1;i++) { max=i; for (j=i+1;j<list_len;j++) { if (list[j].proto_pref>list[max].proto_pref) { max=j; } } if (i!=max) { tmp=list[i]; list[i]=list[max]; list[max]=tmp; } } } return list_len; }
struct hostent* no_naptr_srv_sip_resolvehost(str* name, unsigned short* port, char* proto) { struct dns_srv_proto_t { char proto; int proto_pref; } srv_proto_list[PROTO_LAST], tmp_srv_element; struct hostent* he; struct ip_addr* ip; str srv_name; static char tmp_srv[MAX_DNS_NAME]; /* tmp. buff. for SRV lookups */ int len; unsigned char i,j,max,default_order=0,list_len=0; /* init variables */ he=0; len=0; /* check if it's an ip address */ if (((ip=str2ip(name))!=0) #ifdef USE_IPV6 || ((ip=str2ip6(name))!=0) #endif ){ /* we are lucky, this is an ip address */ /* set proto if needed - default udp */ if ((proto)&&(*proto==PROTO_NONE)) *proto=PROTO_UDP; /* set port if needed - default 5060/5061 */ if ((port)&&(*port==0)) *port=((proto) && (*proto==PROTO_TLS))?SIPS_PORT:SIP_PORT; he=ip_addr2he(name, ip); return he; } if ((name->len+SRV_MAX_PREFIX_LEN+1)>MAX_DNS_NAME){ LOG(L_WARN, "WARNING: no_naptr_srv_sip_resolvehost: domain name too long" " (%d), unable to perform SRV lookup\n", name->len); } else { /* if proto available, then add only the forced protocol to the list */ if (proto && *proto!=PROTO_NONE){ srv_proto_list[0].proto=*proto; list_len=1; } else { /*get protocols and preference scores, and add availble protocol(s) and score(s) to the list*/ for (i=PROTO_UDP; i<PROTO_LAST;i++) { tmp_srv_element.proto_pref = proto_pref_score(i); /* if -1 so disabled continue with next protocol*/ if (naptr_proto_supported(i) == 0 ) { continue; } else { srv_proto_list[i-1].proto_pref=tmp_srv_element.proto_pref; srv_proto_list[i-1].proto=i; list_len++; } }; /* if all protocol prefence scores equal, then set the perference to default values: udp,tcp,tls,sctp */ for (i=1; i<list_len;i++) { if(srv_proto_list[0].proto_pref!=srv_proto_list[i].proto_pref){ default_order=0; } } if (default_order){ for (i=0; i<list_len;i++) { switch ( srv_proto_list[i].proto) { case PROTO_UDP: srv_proto_list[i].proto_pref=4; break; case PROTO_TCP: srv_proto_list[i].proto_pref=3; break; case PROTO_TLS: srv_proto_list[i].proto_pref=2; break; case PROTO_SCTP: srv_proto_list[i].proto_pref=1; break; } } } /* sorting the list */ for (i=0;i<list_len-1;i++) { max=i; for (j=i+1;j<list_len;j++) { if (srv_proto_list[j].proto_pref>srv_proto_list[max].proto_pref) { max=j; } } if (i!=max) { tmp_srv_element=srv_proto_list[i]; srv_proto_list[i]=srv_proto_list[max]; srv_proto_list[max]=tmp_srv_element; } } } /* looping on the ordered list until we found a protocol what has srv record */ for (i=0; i<list_len;i++) { switch (srv_proto_list[i].proto) { case PROTO_NONE: /* no proto specified, use udp */ if (proto) *proto=PROTO_UDP; /* no break */ case PROTO_UDP: memcpy(tmp_srv, SRV_UDP_PREFIX, SRV_UDP_PREFIX_LEN); memcpy(tmp_srv+SRV_UDP_PREFIX_LEN, name->s, name->len); tmp_srv[SRV_UDP_PREFIX_LEN + name->len] = '\0'; len=SRV_UDP_PREFIX_LEN + name->len; break; case PROTO_TCP: memcpy(tmp_srv, SRV_TCP_PREFIX, SRV_TCP_PREFIX_LEN); memcpy(tmp_srv+SRV_TCP_PREFIX_LEN, name->s, name->len); tmp_srv[SRV_TCP_PREFIX_LEN + name->len] = '\0'; len=SRV_TCP_PREFIX_LEN + name->len; break; case PROTO_TLS: memcpy(tmp_srv, SRV_TLS_PREFIX, SRV_TLS_PREFIX_LEN); memcpy(tmp_srv+SRV_TLS_PREFIX_LEN, name->s, name->len); tmp_srv[SRV_TLS_PREFIX_LEN + name->len] = '\0'; len=SRV_TLS_PREFIX_LEN + name->len; break; case PROTO_SCTP: memcpy(tmp_srv, SRV_SCTP_PREFIX, SRV_SCTP_PREFIX_LEN); memcpy(tmp_srv+SRV_SCTP_PREFIX_LEN, name->s, name->len); tmp_srv[SRV_SCTP_PREFIX_LEN + name->len] = '\0'; len=SRV_SCTP_PREFIX_LEN + name->len; break; default: LOG(L_CRIT, "BUG: sip_resolvehost: unknown proto %d\n", (int)srv_proto_list[i].proto); return 0; } /* set default port */ if ((port)&&(*port==0)){ *port=(srv_proto_list[i].proto==PROTO_TLS)?SIPS_PORT:SIP_PORT; /* just in case we don't find another */ } srv_name.s=tmp_srv; srv_name.len=len; #ifdef USE_DNS_CACHE he=dns_srv_get_he(&srv_name, port, dns_flags); #else he=srv_sip_resolvehost(&srv_name, 0, port, proto, 1, 0); #endif if (he!=0) { return he; } } } return 0; }