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; }
/** Resolves SRV if no naptr found. * It reuse dns_pref values and according that resolves supported protocols. * If dns_pref are equal then it use udp,tcp,tls,sctp order. * returns: hostent struct & *port filled with the port from the SRV record; * 0 on error */ struct hostent* no_naptr_srv_sip_resolvehost(str* name, unsigned short* port, char* proto) { struct dns_srv_proto srv_proto_list[PROTO_LAST]; struct hostent* he; struct ip_addr* ip; str srv_name; static char tmp_srv[MAX_DNS_NAME]; /* tmp. buff. for SRV lookups */ size_t i,list_len; /* init variables */ he=0; /* check if it's an ip address */ if (((ip=str2ip(name))!=0) || ((ip=str2ip6(name))!=0) ){ /* 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){ LM_WARN("domain name too long (%d), unable to perform SRV lookup\n", name->len); } else { /* looping on the ordered list until we found a protocol what has srv record */ list_len = create_srv_pref_list(proto, srv_proto_list); for (i=0; i<list_len;i++) { switch (srv_proto_list[i].proto) { case PROTO_UDP: case PROTO_TCP: case PROTO_TLS: case PROTO_SCTP: create_srv_name(srv_proto_list[i].proto, name, tmp_srv); break; default: LM_CRIT("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 */ } if ((proto)&&(*proto==0)){ *proto = PROTO_UDP; } srv_name.s=tmp_srv; srv_name.len=strlen(tmp_srv); #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) { if(proto) *proto = srv_proto_list[i].proto; return he; } } } return 0; }