Mon, 18 Jan 2010 19:47:23 +0100
Import unmodified vendor sources for correction and improvement.
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/opensips/modules/enum/README Mon Jan 18 19:47:23 2010 +0100 1.3 @@ -0,0 +1,311 @@ 1.4 +Enum Module 1.5 + 1.6 +Juha Heinanen 1.7 + 1.8 + <jh@song.fi> 1.9 + 1.10 +Otmar Lendl 1.11 + 1.12 + <lendl@nic.at> 1.13 + 1.14 + Copyright © 2002, 2003 Juha Heinanen 1.15 + Revision History 1.16 + Revision $Revision: 5906 $ $Date: 2009-07-21 10:45:05 +0300 1.17 + (Tue, 21 Jul 2009) $ 1.18 + __________________________________________________________ 1.19 + 1.20 + Table of Contents 1.21 + 1.22 + 1. Admin Guide 1.23 + 1.24 + 1.1. Overview 1.25 + 1.2. Dependencies 1.26 + 1.3. Exported Parameters 1.27 + 1.28 + 1.3.1. domain_suffix (string) 1.29 + 1.3.2. tel_uri_params (string) 1.30 + 1.3.3. i_enum_suffix (string) 1.31 + 1.3.4. branchlabel (string) 1.32 + 1.3.5. bl_algorithm (string) 1.33 + 1.34 + 1.4. Exported Functions 1.35 + 1.36 + 1.4.1. enum_query(["suffix"[,"service"]]) 1.37 + 1.4.2. enum_pv_query("pvar"[,"suffix"[,"service"]]) 1.38 + 1.4.3. i_enum_query(["suffix"[,"service"]]) 1.39 + 1.4.4. is_from_user_enum() 1.40 + 1.41 + List of Examples 1.42 + 1.43 + 1.1. Setting domain_suffix module parameter 1.44 + 1.2. Setting tel_uri_params module parameter 1.45 + 1.3. Setting i_enum_suffix module parameter 1.46 + 1.4. Setting brachlabel module parameter 1.47 + 1.5. Zone file example 1.48 + 1.6. Zone file example 1.49 + 1.7. Setting the bl_algorithm module parameter 1.50 + 1.8. enum_query usage 1.51 + 1.9. enum_pv_query usage 1.52 + 1.10. is_from_user_enum usage 1.53 + 1.54 +Chapter 1. Admin Guide 1.55 + 1.56 +1.1. Overview 1.57 + 1.58 + Enum module implements [i_]enum_query functions that make an 1.59 + enum query based on the user part of the current Request-URI. 1.60 + These functions assume that the user part consists of an 1.61 + international phone number of the form +decimal-digits, where 1.62 + the number of digits is at least 2 and at most 15. Out of this 1.63 + number enum_query forms a domain name, where the digits are in 1.64 + reverse order and separated by dots followed by domain suffix 1.65 + that by default is "e164.arpa.". For example, if the user part 1.66 + is +35831234567, the domain name will be 1.67 + "7.6.5.4.3.2.1.3.8.5.3.e164.arpa.". i_enum_query operates in a 1.68 + similar fashion. The only difference is that it adds a label 1.69 + (default "i") to branch off from the default, user-ENUM tree to 1.70 + an infrastructure ENUM tree. 1.71 + 1.72 + After forming the domain name, enum_query queries DNS for its 1.73 + NAPTR records. From the possible response enum_query chooses 1.74 + those records, whose flags field has string value "u", and 1.75 + whose services field has string value "e2u+[service:]sip" or 1.76 + "e2u+type[:subtype][+type[:subtype]...]" (case is ignored in 1.77 + both cases), and whose regexp field is of the form 1.78 + !pattern!replacement!. 1.79 + 1.80 + Then enum_query sorts the chosen NAPTR records based on their 1.81 + <order, preference>. After sorting, enum_query replaces the 1.82 + current Request URI by applying regexp of the most preferred 1.83 + NAPTR record its user part and appends to the request new 1.84 + branches by applying regexp of each remaining NAPTR record to 1.85 + the user part of the current Request URI. If a new URI is a tel 1.86 + URI, enum_query appends to it as tel URI parameters the value 1.87 + of tel_uri_params module parameter. Finally, enum_query 1.88 + associates a q value with each new URI based on the <order, 1.89 + preference> of the corresponding NAPTR record. 1.90 + 1.91 + When using enum_query without any parameters, it searches for 1.92 + NAPTRs with service type "e2u+sip" in the default enum tree. 1.93 + When using enum_query with a single parameter, this parameter 1.94 + will be used as enum tree. When using enum_query with two 1.95 + parameters, the functionality depends on the first letter in 1.96 + the second parameter. When the first letter is not a '+' sign, 1.97 + the second parameter will be used to search for NAPTRs with 1.98 + service type "e2u+parameter:sip". When the second parameter 1.99 + starts with a '+' sign, the ENUM lookup also supports compound 1.100 + NAPTRs (e.g. "e2u+voice:sip+video:sip") and searching for 1.101 + multiple service types within one lookup. Multiple service 1.102 + types must be separeted by a '+' sign. 1.103 + 1.104 + Most of the time you want to route based on the RURI. On rare 1.105 + occasions you may wish to route based on something else. The 1.106 + function enum_pv_query mimics the behavior of the enum_query 1.107 + function except the E.164 number in its pseudo variable 1.108 + argument is used for the enum lookup instead of the user part 1.109 + of the RURI. Obviously the user part of the RURI is still used 1.110 + in the NAPTR regexp. 1.111 + 1.112 + Enum query returns 1 if the current Request URI was replaced 1.113 + and -1 if not. 1.114 + 1.115 + Enum module also implements is_from_user_enum function. This 1.116 + function does an enum lookup on the from user and returns true 1.117 + if found, false otherwise. 1.118 + 1.119 +1.2. Dependencies 1.120 + 1.121 + The module depends on the following modules (in the other words 1.122 + the listed modules must be loaded before this module): 1.123 + * No dependencies. 1.124 + 1.125 +1.3. Exported Parameters 1.126 + 1.127 +1.3.1. domain_suffix (string) 1.128 + 1.129 + The domain suffix to be added to the domain name obtained from 1.130 + the digits of an E164 number. Can be overridden by a parameter 1.131 + to enum_query. 1.132 + 1.133 + Default value is "e164.arpa." 1.134 + 1.135 + Example 1.1. Setting domain_suffix module parameter 1.136 +modparam("enum", "domain_suffix", "e1234.arpa.") 1.137 + 1.138 +1.3.2. tel_uri_params (string) 1.139 + 1.140 + A string whose contents is appended to each new tel URI in the 1.141 + request as tel URI parameters. 1.142 + 1.143 +Note 1.144 + 1.145 + Currently OpenSIPS does not support tel URIs. This means that 1.146 + at present tel_uri_params is appended as URI parameters to 1.147 + every URI. 1.148 + 1.149 + Default value is "" 1.150 + 1.151 + Example 1.2. Setting tel_uri_params module parameter 1.152 +modparam("enum", "tel_uri_params", ";npdi") 1.153 + 1.154 +1.3.3. i_enum_suffix (string) 1.155 + 1.156 + The domain suffix to be used for i_enum_query() lookups. Can be 1.157 + overridden by a parameter to i_enum_query. 1.158 + 1.159 + Default value is "e164.arpa." 1.160 + 1.161 + Example 1.3. Setting i_enum_suffix module parameter 1.162 +modparam("enum", "i_enum_suffix", "e1234.arpa.") 1.163 + 1.164 +1.3.4. branchlabel (string) 1.165 + 1.166 + This parameter determines which label i_enum_query() will use 1.167 + to branch off to the infrastructure ENUM tree. 1.168 + 1.169 + Default value is ""i"" 1.170 + 1.171 + Example 1.4. Setting brachlabel module parameter 1.172 +modparam("enum", "branchlabel", "i") 1.173 + 1.174 +1.3.5. bl_algorithm (string) 1.175 + 1.176 + This parameter determines which algorithm i_enum_query() will 1.177 + use to select the position in the DNS tree where the 1.178 + infrastructure tree branches off the user ENUM tree. 1.179 + 1.180 + If set to "cc", i_enum_query() will always inserts the label at 1.181 + the country-code level. Examples: i.1.e164.arpa, 1.182 + i.3.4.e164.arpa, i.2.5.3.e164.arpa 1.183 + 1.184 + If set to "txt", i_enum_query() will look for a TXT record at 1.185 + [branchlabel].[reverse-country-code].[i_enum_suffix] to 1.186 + indicate after how many digits the label should in inserted. 1.187 + 1.188 + Example 1.5. Zone file example 1.189 +i.1.e164.arpa. IN TXT "4" 1.190 +9.9.9.8.7.6.5.i.4.3.2.1.e164.arpa. IN NAPTR "NAPTR content for +1 234 5 1.191 +678 999" 1.192 + 1.193 + If set to "ebl", i_enum_query() will look for an EBL (ENUM 1.194 + Branch Label) record at 1.195 + [branchlabel].[reverse-country-code].[i_enum_suffix]. See 1.196 + http://www.ietf.org/internet-drafts/draft-lendl-enum-branch-loc 1.197 + ation-record-00.txt for a description of that record and the 1.198 + meaning of the fields. The RR type for the EBL has not been 1.199 + allocated yet. This version of the code uses 65300. See 1.200 + resolve.h. 1.201 + 1.202 + Example 1.6. Zone file example 1.203 +i.1.e164.arpa. TYPE65300 \# 14 ( 1.204 + 04 ; position 1.205 + 01 69 ; separator 1.206 + 04 65 31 36 34 04 61 72 70 61 00 ; e164.ar 1.207 +pa 1.208 +; ) 1.209 +9.9.9.8.7.6.5.i.4.3.2.1.e164.arpa. IN NAPTR "NAPTR content for +1 234 5 1.210 +678 999" 1.211 + 1.212 + Default value is "cc" 1.213 + 1.214 + Example 1.7. Setting the bl_algorithm module parameter 1.215 +modparam("enum", "bl_algorithm", "txt") 1.216 + 1.217 +1.4. Exported Functions 1.218 + 1.219 +1.4.1. enum_query(["suffix"[,"service"]]) 1.220 + 1.221 + The function performs an enum query and rewrites the 1.222 + Request-URI with the result of the query. See Section 1.1, 1.223 + "Overview" for more information. 1.224 + 1.225 + Meaning of the parameters is as follows: 1.226 + * suffix - Suffix to be appended to the domain name. 1.227 + * service - Service string to be used in the service field. 1.228 + 1.229 + This function can be used from REQUEST_ROUTE. 1.230 + 1.231 + Example 1.8. enum_query usage 1.232 +... 1.233 +# search for "e2u+sip" in freenum.org 1.234 +enum_query("freenum.org."); 1.235 +... 1.236 +# search for "e2u+sip" in default tree (configured as parameter) 1.237 +enum_query(); 1.238 +... 1.239 +# search for "e2u+voice:sip" in e164.arpa 1.240 +enum_query("e164.arpa.","voice"); 1.241 +... 1.242 +# search for service type "sip" or "voice:sip" or "video:sip" 1.243 +# note the '+' sign in front of the second parameter 1.244 +enum_query("e164.arpa.","+sip+voice:sip+video:sip"); 1.245 +... 1.246 +# quering for service sip and voice:sip 1.247 +enum_query("e164.arpa."); 1.248 +enum_query("e164.arpa.","voice"); 1.249 +# or use instead 1.250 +enum_query("e164.arpa.","+sip+voice:sip"); 1.251 +... 1.252 + 1.253 +1.4.2. enum_pv_query("pvar"[,"suffix"[,"service"]]) 1.254 + 1.255 + The function performs an enum query on E.164 number stored in 1.256 + its pseudo variable argument and rewrites the Request-URI with 1.257 + the result of the query. See Section 1.1, "Overview" for more 1.258 + information. 1.259 + 1.260 + Meaning of the parameters is as follows: 1.261 + * pvar - Pseudo variable that holds an E.164 number on which 1.262 + enum query is performed. 1.263 + * suffix - Suffix to be appended to the domain name. 1.264 + * service - Service string to be used in the service field. 1.265 + 1.266 + This function can be used from REQUEST_ROUTE. 1.267 + 1.268 + Example 1.9. enum_pv_query usage 1.269 +... 1.270 +# search for "e2u+sip" in freenum.org 1.271 +enum_pv_query("$avp(i:100)", "freenum.org."); 1.272 +... 1.273 +# search for "e2u+sip" in default tree (configured as parameter) 1.274 +enum_pv_query("$fU"); 1.275 +... 1.276 +# search for "e2u+voice:sip" in e164.arpa 1.277 +enum_pv_query("$avp(i:100)","e164.arpa.","voice"); 1.278 +... 1.279 +# search for service type "sip" or "voice:sip" or "video:sip" 1.280 +# note the '+' sign in front of the second parameter 1.281 +enum_pv_query("$fU","e164.arpa.","+sip+voice:sip+video:sip"); 1.282 +... 1.283 +# quering for service sip and voice:sip 1.284 +enum_pv_query("$avp(i:100)","e164.arpa."); 1.285 +enum_pv_query("$avp(i:100)","e164.arpa.","voice"); 1.286 +# or use instead 1.287 +enum_pv_query("$avp(i:100)","e164.arpa.","+sip+voice:sip"); 1.288 +... 1.289 + 1.290 +1.4.3. i_enum_query(["suffix"[,"service"]]) 1.291 + 1.292 + The function performs an enum query and rewrites the 1.293 + Request-URI with the result of the query. This the 1.294 + Infrastructure-ENUM version of enum_query(). The only 1.295 + difference to enum_query() is in the calculation of the FQDN 1.296 + where NAPTR records are looked for. 1.297 + 1.298 + See 1.299 + ftp://ftp.rfc-editor.org/in-notes/internet-drafts/draft-haberle 1.300 + r-carrier-enum-01.txt for the rationale behind this function. 1.301 + 1.302 +1.4.4. is_from_user_enum() 1.303 + 1.304 + Checks if the user part of from URI is found in an enum lookup. 1.305 + Returns 1 if yes and -1 if not. 1.306 + 1.307 + This function can be used from REQUEST_ROUTE. 1.308 + 1.309 + Example 1.10. is_from_user_enum usage 1.310 +... 1.311 +if (is_from_user_enum()) { 1.312 + .... 1.313 +}; 1.314 +...
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/opensips/modules/enum/doc/enum.xml Mon Jan 18 19:47:23 2010 +0100 2.3 @@ -0,0 +1,46 @@ 2.4 +<?xml version="1.0" encoding='ISO-8859-1'?> 2.5 +<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" 2.6 +"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [ 2.7 + 2.8 +<!ENTITY admin SYSTEM "enum_admin.xml"> 2.9 +<!ENTITY faq SYSTEM "../../../doc/module_faq.xml"> 2.10 + 2.11 +<!-- Include general documentation entities --> 2.12 +<!ENTITY % docentities SYSTEM "../../../doc/entities.xml"> 2.13 +%docentities; 2.14 + 2.15 +]> 2.16 + 2.17 +<book> 2.18 + <bookinfo> 2.19 + <title>Enum Module</title> 2.20 + <authorgroup> 2.21 + <author> 2.22 + <firstname>Juha</firstname> 2.23 + <surname>Heinanen</surname> 2.24 + <email>jh@song.fi</email> 2.25 + </author> 2.26 + <author> 2.27 + <firstname>Otmar</firstname> 2.28 + <surname>Lendl</surname> 2.29 + <email>lendl@nic.at</email> 2.30 + </author> 2.31 + </authorgroup> 2.32 + <copyright> 2.33 + <year>2002</year> 2.34 + <year>2003</year> 2.35 + <holder>Juha Heinanen</holder> 2.36 + </copyright> 2.37 + <revhistory> 2.38 + <revision> 2.39 + <revnumber>$Revision: 5901 $</revnumber> 2.40 + <date>$Date: 2009-07-21 10:45:05 +0300 (Tue, 21 Jul 2009) $</date> 2.41 + </revision> 2.42 + </revhistory> 2.43 + </bookinfo> 2.44 + <toc></toc> 2.45 + 2.46 + &admin; 2.47 + &faq; 2.48 + 2.49 +</book>
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/opensips/modules/enum/doc/enum_admin.xml Mon Jan 18 19:47:23 2010 +0100 3.3 @@ -0,0 +1,378 @@ 3.4 +<!-- Enum Module User's Guide --> 3.5 + 3.6 +<chapter> 3.7 + 3.8 + <title>&adminguide;</title> 3.9 + 3.10 + <section id="sec-overview"> 3.11 + <title>Overview</title> 3.12 + <para> 3.13 + Enum module implements [i_]enum_query functions that make an enum query 3.14 + based on the user part of the current Request-URI. These functions 3.15 + assume that the user part consists of an international phone number 3.16 + of the form +decimal-digits, where the number of digits is at 3.17 + least 2 and at most 15. Out of this number 3.18 + <function moreinfo="none">enum_query</function> forms a domain name, 3.19 + where the digits are in reverse order and separated by dots followed by 3.20 + domain suffix that by default is <quote>e164.arpa.</quote>. For example, 3.21 + if the user part is +35831234567, the domain 3.22 + name will be <quote>7.6.5.4.3.2.1.3.8.5.3.e164.arpa.</quote>. 3.23 + <function moreinfo="none">i_enum_query</function> operates in a similar 3.24 + fashion. The only difference is that it adds a label (default "i") 3.25 + to branch off from the default, user-ENUM tree to an infrastructure ENUM tree. 3.26 + </para> 3.27 + <para> 3.28 + After forming the domain name, 3.29 + <function moreinfo="none">enum_query</function> queries 3.30 + DNS for its NAPTR records. From the possible response 3.31 + <function moreinfo="none">enum_query</function> chooses those records, 3.32 + whose flags field has string value "u", and whose services field has 3.33 + string value "e2u+[service:]sip" or 3.34 + "e2u+type[:subtype][+type[:subtype]...]" (case is ignored in both 3.35 + cases), and whose regexp field is of the form !pattern!replacement!. 3.36 + </para> 3.37 + <para> 3.38 + Then <function moreinfo="none">enum_query</function> sorts the chosen 3.39 + NAPTR records based on their <order, preference>. After sorting, 3.40 + <function moreinfo="none">enum_query</function> replaces the current 3.41 + Request URI by applying regexp of the most preferred NAPTR record its 3.42 + user part and appends to the request new branches by applying regexp of 3.43 + each remaining NAPTR record to the user part of the 3.44 + current Request URI. If a new URI is a tel URI, 3.45 + <function moreinfo="none">enum_query</function> appends to it as tel 3.46 + URI parameters the value of tel_uri_params module parameter. Finally, 3.47 + <function moreinfo="none">enum_query</function> associates a q value 3.48 + with each new URI based on the <order, preference> of the 3.49 + corresponding NAPTR record. 3.50 + </para> 3.51 + <para> 3.52 + When using <function moreinfo="none">enum_query</function> without any 3.53 + parameters, it searches for NAPTRs with service type "e2u+sip" in the 3.54 + default enum tree. When using 3.55 + <function moreinfo="none">enum_query</function> with a single parameter, 3.56 + this parameter will be used as enum tree. When using 3.57 + <function moreinfo="none">enum_query</function> 3.58 + with two parameters, the functionality depends on the first letter in 3.59 + the second parameter. When the first letter is not a '+' sign, the 3.60 + second parameter will be used to search for NAPTRs with service type 3.61 + "e2u+parameter:sip". When the second parameter starts with a '+' sign, 3.62 + the ENUM lookup also supports compound NAPTRs 3.63 + (e.g. "e2u+voice:sip+video:sip") and searching for multiple service 3.64 + types within one lookup. Multiple service types must be separeted 3.65 + by a '+' sign. 3.66 + </para> 3.67 + <para> 3.68 + Most of the time you want to route based on the RURI. On rare occasions 3.69 + you may wish to route based on something else. The function 3.70 + <function moreinfo="none">enum_pv_query</function> mimics the behavior 3.71 + of the <function moreinfo="none">enum_query</function> function except the 3.72 + E.164 number in its pseudo variable argument is used for the enum lookup instead of the user 3.73 + part of the RURI. Obviously the user part of the RURI is still used in the 3.74 + NAPTR regexp. 3.75 + </para> 3.76 + <para> 3.77 + Enum query returns 1 if the current Request URI was replaced 3.78 + and -1 if not. 3.79 + </para> 3.80 + <para> 3.81 + Enum module also implements is_from_user_enum function. 3.82 + This function does an enum lookup on the from user and 3.83 + returns true if found, false otherwise. 3.84 + </para> 3.85 + </section> 3.86 + 3.87 + <section> 3.88 + <title>Dependencies</title> 3.89 + <para> 3.90 + The module depends on the following modules (in the other words the 3.91 + listed modules must be loaded before this module): 3.92 + <itemizedlist> 3.93 + <listitem> 3.94 + <para>No dependencies.</para> 3.95 + </listitem> 3.96 + </itemizedlist> 3.97 + </para> 3.98 + </section> 3.99 + 3.100 + <section> 3.101 + <title>Exported Parameters</title> 3.102 + <section> 3.103 + <title><varname>domain_suffix</varname> (string)</title> 3.104 + <para> 3.105 + The domain suffix to be added to the domain name obtained from 3.106 + the digits of an <acronym>E164</acronym> number. Can be overridden 3.107 + by a parameter to enum_query. 3.108 + </para> 3.109 + <para> 3.110 + Default value is <quote>e164.arpa.</quote> 3.111 + </para> 3.112 + <example> 3.113 + <title>Setting domain_suffix module parameter</title> 3.114 + <programlisting format="linespecific"> 3.115 +modparam("enum", "domain_suffix", "e1234.arpa.") 3.116 +</programlisting> 3.117 + </example> 3.118 + </section> 3.119 + 3.120 + <section> 3.121 + <title><varname>tel_uri_params</varname> (string)</title> 3.122 + <para> 3.123 + A string whose contents is appended to each new tel URI in the 3.124 + request as tel URI parameters. 3.125 + </para> 3.126 + <note> 3.127 + <para> 3.128 + Currently &osips; does not support tel URIs. This means that at present 3.129 + tel_uri_params is appended as URI parameters to every URI. 3.130 + </para> 3.131 + </note> 3.132 + <para> 3.133 + Default value is <quote></quote> 3.134 + </para> 3.135 + <example> 3.136 + <title>Setting tel_uri_params module parameter</title> 3.137 + <programlisting format="linespecific"> 3.138 +modparam("enum", "tel_uri_params", ";npdi") 3.139 +</programlisting> 3.140 + </example> 3.141 + </section> 3.142 + <section> 3.143 + <title><varname>i_enum_suffix</varname> (string)</title> 3.144 + <para> 3.145 + The domain suffix to be used for i_enum_query() lookups. 3.146 + Can be overridden by a parameter to i_enum_query. 3.147 + </para> 3.148 + <para> 3.149 + Default value is <quote>e164.arpa.</quote> 3.150 + </para> 3.151 + <example> 3.152 + <title>Setting i_enum_suffix module parameter</title> 3.153 + <programlisting format="linespecific"> 3.154 +modparam("enum", "i_enum_suffix", "e1234.arpa.") 3.155 +</programlisting> 3.156 + </example> 3.157 + </section> 3.158 + <section> 3.159 + <title><varname>branchlabel</varname> (string)</title> 3.160 + <para> 3.161 + This parameter determines which label i_enum_query() will use 3.162 + to branch off to the infrastructure ENUM tree. 3.163 + </para> 3.164 + <para> 3.165 + Default value is <quote>"i"</quote> 3.166 + </para> 3.167 + <example> 3.168 + <title>Setting brachlabel module parameter</title> 3.169 + <programlisting format="linespecific"> 3.170 +modparam("enum", "branchlabel", "i") 3.171 +</programlisting> 3.172 + </example> 3.173 + </section> 3.174 + <section> 3.175 + <title><varname>bl_algorithm</varname> (string)</title> 3.176 + <para> 3.177 + This parameter determines which algorithm i_enum_query() will use 3.178 + to select the position in the DNS tree where the infrastructure tree 3.179 + branches off the user ENUM tree. 3.180 + </para> 3.181 + <para> 3.182 + If set to "cc", i_enum_query() will always inserts the 3.183 + label at the country-code level. 3.184 + Examples: i.1.e164.arpa, i.3.4.e164.arpa, i.2.5.3.e164.arpa 3.185 + </para> 3.186 + <para> 3.187 + If set to "txt", i_enum_query() will look for a TXT record at 3.188 + [branchlabel].[reverse-country-code].[i_enum_suffix] to indicate after how many digits the 3.189 + label should in inserted. 3.190 + <example> 3.191 + <title>Zone file example</title> 3.192 + <programlisting format="linespecific"> 3.193 +i.1.e164.arpa. IN TXT "4" 3.194 +9.9.9.8.7.6.5.i.4.3.2.1.e164.arpa. IN NAPTR "NAPTR content for +1 234 5678 999" 3.195 +</programlisting> 3.196 + </example> 3.197 + </para> 3.198 + <para> 3.199 + If set to "ebl", i_enum_query() will look for an EBL (ENUM Branch Label) record at 3.200 + [branchlabel].[reverse-country-code].[i_enum_suffix]. See http://www.ietf.org/internet-drafts/draft-lendl-enum-branch-location-record-00.txt for a description of that record and the 3.201 + meaning of the fields. The RR type for the EBL has not been allocated yet. 3.202 + This version of the code uses 65300. See resolve.h. 3.203 + <example> 3.204 + <title>Zone file example</title> 3.205 + <programlisting format="linespecific"> 3.206 +i.1.e164.arpa. TYPE65300 \# 14 ( 3.207 + 04 ; position 3.208 + 01 69 ; separator 3.209 + 04 65 31 36 34 04 61 72 70 61 00 ; e164.arpa 3.210 +; ) 3.211 +9.9.9.8.7.6.5.i.4.3.2.1.e164.arpa. IN NAPTR "NAPTR content for +1 234 5678 999" 3.212 +</programlisting> 3.213 + </example> 3.214 + </para> 3.215 + 3.216 + <para> 3.217 + Default value is <quote>cc</quote> 3.218 + </para> 3.219 + <example> 3.220 + <title>Setting the bl_algorithm module parameter</title> 3.221 + <programlisting format="linespecific"> 3.222 +modparam("enum", "bl_algorithm", "txt") 3.223 +</programlisting> 3.224 + </example> 3.225 + </section> 3.226 + 3.227 + </section> 3.228 + 3.229 + <section> 3.230 + <title>Exported Functions</title> 3.231 + <section> 3.232 + <title> 3.233 + <function moreinfo="none">enum_query(["suffix"[,"service"]])</function> 3.234 + </title> 3.235 + <para> 3.236 + The function performs an enum query and rewrites the Request-URI with 3.237 + the result of the query. See <xref linkend="sec-overview"/> for more 3.238 + information. 3.239 + </para> 3.240 + <para>Meaning of the parameters is as follows:</para> 3.241 + <itemizedlist> 3.242 + <listitem> 3.243 + <para><emphasis>suffix</emphasis> - Suffix to be appended to the 3.244 + domain name. 3.245 + </para> 3.246 + </listitem> 3.247 + <listitem> 3.248 + <para><emphasis>service</emphasis> - Service string to be used in 3.249 + the service field. 3.250 + </para> 3.251 + </listitem> 3.252 + </itemizedlist> 3.253 + <para> 3.254 + This function can be used from REQUEST_ROUTE. 3.255 + </para> 3.256 + <example> 3.257 + <title><function moreinfo="none">enum_query</function> usage</title> 3.258 + <programlisting format="linespecific"> 3.259 +... 3.260 +# search for "e2u+sip" in freenum.org 3.261 +enum_query("freenum.org."); 3.262 +... 3.263 +# search for "e2u+sip" in default tree (configured as parameter) 3.264 +enum_query(); 3.265 +... 3.266 +# search for "e2u+voice:sip" in e164.arpa 3.267 +enum_query("e164.arpa.","voice"); 3.268 +... 3.269 +# search for service type "sip" or "voice:sip" or "video:sip" 3.270 +# note the '+' sign in front of the second parameter 3.271 +enum_query("e164.arpa.","+sip+voice:sip+video:sip"); 3.272 +... 3.273 +# quering for service sip and voice:sip 3.274 +enum_query("e164.arpa."); 3.275 +enum_query("e164.arpa.","voice"); 3.276 +# or use instead 3.277 +enum_query("e164.arpa.","+sip+voice:sip"); 3.278 +... 3.279 +</programlisting> 3.280 + </example> 3.281 + </section> 3.282 + 3.283 + <section> 3.284 + <title> 3.285 + <function moreinfo="none">enum_pv_query("pvar"[,"suffix"[,"service"]])</function> 3.286 + </title> 3.287 + <para> 3.288 + The function performs an enum query on E.164 number stored 3.289 + in its pseudo variable argument and rewrites the Request-URI with 3.290 + the result of the query. See <xref linkend="sec-overview"/> for more 3.291 + information. 3.292 + </para> 3.293 + <para>Meaning of the parameters is as follows:</para> 3.294 + <itemizedlist> 3.295 + <listitem> 3.296 + <para><emphasis>pvar</emphasis> - Pseudo 3.297 + variable that holds an E.164 number on which enum 3.298 + query is performed. 3.299 + </para> 3.300 + </listitem> 3.301 + <listitem> 3.302 + <para><emphasis>suffix</emphasis> - Suffix to be appended to the 3.303 + domain name. 3.304 + </para> 3.305 + </listitem> 3.306 + <listitem> 3.307 + <para><emphasis>service</emphasis> - Service string to be used in 3.308 + the service field. 3.309 + </para> 3.310 + </listitem> 3.311 + </itemizedlist> 3.312 + <para> 3.313 + This function can be used from REQUEST_ROUTE. 3.314 + </para> 3.315 + <example> 3.316 + <title><function moreinfo="none">enum_pv_query</function> usage</title> 3.317 + <programlisting format="linespecific"> 3.318 +... 3.319 +# search for "e2u+sip" in freenum.org 3.320 +enum_pv_query("$avp(i:100)", "freenum.org."); 3.321 +... 3.322 +# search for "e2u+sip" in default tree (configured as parameter) 3.323 +enum_pv_query("$fU"); 3.324 +... 3.325 +# search for "e2u+voice:sip" in e164.arpa 3.326 +enum_pv_query("$avp(i:100)","e164.arpa.","voice"); 3.327 +... 3.328 +# search for service type "sip" or "voice:sip" or "video:sip" 3.329 +# note the '+' sign in front of the second parameter 3.330 +enum_pv_query("$fU","e164.arpa.","+sip+voice:sip+video:sip"); 3.331 +... 3.332 +# quering for service sip and voice:sip 3.333 +enum_pv_query("$avp(i:100)","e164.arpa."); 3.334 +enum_pv_query("$avp(i:100)","e164.arpa.","voice"); 3.335 +# or use instead 3.336 +enum_pv_query("$avp(i:100)","e164.arpa.","+sip+voice:sip"); 3.337 +... 3.338 +</programlisting> 3.339 + </example> 3.340 + </section> 3.341 + 3.342 + <section> 3.343 + <title> 3.344 + <function moreinfo="none">i_enum_query(["suffix"[,"service"]])</function> 3.345 + </title> 3.346 + <para> 3.347 + The function performs an enum query and rewrites the Request-URI with 3.348 + the result of the query. This the Infrastructure-ENUM version of enum_query(). 3.349 + The only difference to enum_query() is in the calculation of the 3.350 + FQDN where NAPTR records are looked for. 3.351 + </para> 3.352 + <para> 3.353 + See ftp://ftp.rfc-editor.org/in-notes/internet-drafts/draft-haberler-carrier-enum-01.txt 3.354 + for the rationale behind this function. 3.355 + </para> 3.356 + </section> 3.357 + 3.358 + <section> 3.359 + <title><function moreinfo="none">is_from_user_enum()</function></title> 3.360 + <para> 3.361 + Checks if the user part of from <abbrev>URI</abbrev> 3.362 + is found in an enum lookup. 3.363 + Returns 1 if yes and -1 if not. 3.364 + </para> 3.365 + <para> 3.366 + This function can be used from REQUEST_ROUTE. 3.367 + </para> 3.368 + <example> 3.369 + <title><function moreinfo="none">is_from_user_enum</function> usage</title> 3.370 + <programlisting format="linespecific"> 3.371 +... 3.372 +if (is_from_user_enum()) { 3.373 + .... 3.374 +}; 3.375 +... 3.376 +</programlisting> 3.377 + </example> 3.378 + </section> 3.379 + </section> 3.380 +</chapter> 3.381 +
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/opensips/modules/enum/enum.c Mon Jan 18 19:47:23 2010 +0100 4.3 @@ -0,0 +1,1118 @@ 4.4 +/* 4.5 + * $Id: enum.c 5901 2009-07-21 07:45:05Z bogdan_iancu $ 4.6 + * 4.7 + * Enum and E164 related functions 4.8 + * 4.9 + * Copyright (C) 2002-2008 Juha Heinanen 4.10 + * 4.11 + * This file is part of opensips, a free SIP server. 4.12 + * 4.13 + * opensips is free software; you can redistribute it and/or modify 4.14 + * it under the terms of the GNU General Public License as published by 4.15 + * the Free Software Foundation; either version 2 of the License, or 4.16 + * (at your option) any later version 4.17 + * 4.18 + * opensips is distributed in the hope that it will be useful, 4.19 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 4.20 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 4.21 + * GNU General Public License for more details. 4.22 + * 4.23 + * You should have received a copy of the GNU General Public License 4.24 + * along with this program; if not, write to the Free Software 4.25 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 4.26 + * 4.27 + */ 4.28 + 4.29 +#include <stdlib.h> 4.30 + 4.31 +#include "enum.h" 4.32 +#include "../../parser/parse_uri.h" 4.33 +#include "../../parser/parse_from.h" 4.34 +#include "../../ut.h" 4.35 +#include "../../resolve.h" 4.36 +#include "../../mem/mem.h" 4.37 +#include "../../dset.h" 4.38 +#include "../../qvalue.h" 4.39 +#include "enum_mod.h" 4.40 +#include "../../regexp.h" 4.41 +#include "../../pvar.h" 4.42 + 4.43 +/* 4.44 + * Input: E.164 number w/o leading + 4.45 + * 4.46 + * Output: number of digits in the country code 4.47 + * 0 on invalid number 4.48 + * 4.49 + * convention: 4.50 + * 3 digits is the default length of a country code. 4.51 + * country codes 1 and 7 are a single digit. 4.52 + * the following country codes are two digits: 20, 27, 30-34, 36, 39, 4.53 + * 40, 41, 43-49, 51-58, 60-66, 81, 82, 84, 86, 90-95, 98. 4.54 + */ 4.55 +static int cclen(const char *number) 4.56 +{ 4.57 + char d1,d2; 4.58 + 4.59 + if (!number || (strlen(number) < 3)) 4.60 + return(0); 4.61 + 4.62 + d1 = number[0]; 4.63 + d2 = number[1]; 4.64 + 4.65 + if (!isdigit((int)d2)) 4.66 + return(0); 4.67 + 4.68 + switch(d1) { 4.69 + case '1': 4.70 + case '7': 4.71 + return(1); 4.72 + case '2': 4.73 + if ((d2 == '0') || (d1 == '7')) 4.74 + return(2); 4.75 + break; 4.76 + case '3': 4.77 + if ((d2 >= '0') && (d1 <= '4')) 4.78 + return(2); 4.79 + if ((d2 == '6') || (d1 == '9')) 4.80 + return(2); 4.81 + break; 4.82 + case '4': 4.83 + if (d2 != '2') 4.84 + return(2); 4.85 + break; 4.86 + case '5': 4.87 + if ((d2 >= '1') && (d1 <= '8')) 4.88 + return(2); 4.89 + break; 4.90 + case '6': 4.91 + if (d1 <= '6') 4.92 + return(2); 4.93 + break; 4.94 + case '8': 4.95 + if ((d2 == '1') || (d1 == '2') || (d1 == '4') || (d1 == '6')) 4.96 + return(2); 4.97 + break; 4.98 + case '9': 4.99 + if (d1 <= '5') 4.100 + return(2); 4.101 + if (d2 == '8') 4.102 + return(2); 4.103 + break; 4.104 + default: 4.105 + return(0); 4.106 + } 4.107 + 4.108 + return(3); 4.109 +} 4.110 + 4.111 + 4.112 + 4.113 +/* return the length of the string until c, if not found returns n */ 4.114 +static inline int findchr(char* p, int c, unsigned int size) 4.115 +{ 4.116 + int len=0; 4.117 + 4.118 + for(;len<size;p++){ 4.119 + if (*p==(unsigned char)c) { 4.120 + return len; 4.121 + } 4.122 + len++; 4.123 + } 4.124 + return len; 4.125 +} 4.126 + 4.127 + 4.128 +/* Parse NAPTR regexp field of the form !pattern!replacement! and return its 4.129 + * components in pattern and replacement parameters. Regexp field starts at 4.130 + * address first and is len characters long. 4.131 + */ 4.132 +static inline int parse_naptr_regexp(char* first, int len, str* pattern, 4.133 + str* replacement) 4.134 +{ 4.135 + char *second, *third; 4.136 + 4.137 + if (len > 0) { 4.138 + if (*first == '!') { 4.139 + second = (char *)memchr((void *)(first + 1), '!', len - 1); 4.140 + if (second) { 4.141 + len = len - (second - first + 1); 4.142 + if (len > 0) { 4.143 + third = memchr(second + 1, '!', len); 4.144 + if (third) { 4.145 + pattern->len = second - first - 1; 4.146 + pattern->s = first + 1; 4.147 + replacement->len = third - second - 1; 4.148 + replacement->s = second + 1; 4.149 + return 1; 4.150 + } else { 4.151 + LM_ERR("Third ! missing from regexp\n"); 4.152 + return -1; 4.153 + } 4.154 + } else { 4.155 + LM_ERR("Third ! missing from regexp\n"); 4.156 + return -2; 4.157 + } 4.158 + } else { 4.159 + LM_ERR("Second ! missing from regexp\n"); 4.160 + return -3; 4.161 + } 4.162 + } else { 4.163 + LM_ERR("First ! missing from regexp\n"); 4.164 + return -4; 4.165 + } 4.166 + } else { 4.167 + LM_ERR("Regexp missing\n"); 4.168 + return -5; 4.169 + } 4.170 +} 4.171 +/* Checks if NAPTR record has flag u and its services field 4.172 + * e2u+[service:]sip or 4.173 + * e2u+service[+service[+service[+...]]] 4.174 + */ 4.175 +static inline int sip_match( struct naptr_rdata* naptr, str* service) 4.176 +{ 4.177 + if (service->len == 0) { 4.178 + return (naptr->flags_len == 1) && 4.179 + ((naptr->flags[0] == 'u') || (naptr->flags[0] == 'U')) && 4.180 + (naptr->services_len == 7) && 4.181 + ((strncasecmp(naptr->services, "e2u+sip", 7) == 0) || 4.182 + (strncasecmp(naptr->services, "sip+e2u", 7) == 0)); 4.183 + } else if (service->s[0] != '+') { 4.184 + return (naptr->flags_len == 1) && 4.185 + ((naptr->flags[0] == 'u') || (naptr->flags[0] == 'U')) && 4.186 + (naptr->services_len == service->len + 8) && 4.187 + (strncasecmp(naptr->services, "e2u+", 4) == 0) && 4.188 + (strncasecmp(naptr->services + 4, service->s, service->len) == 0) && 4.189 + (strncasecmp(naptr->services + 4 + service->len, ":sip", 4) == 0); 4.190 + } else { /* handle compound NAPTRs and multiple services */ 4.191 + str bakservice, baknaptr; /* we bakup the str */ 4.192 + int naptrlen, len; /* length of the extracted service */ 4.193 + 4.194 + /* RFC 3761, NAPTR service field must start with E2U+ */ 4.195 + if (strncasecmp(naptr->services, "e2u+", 4) != 0) { 4.196 + return 0; 4.197 + } 4.198 + baknaptr.s = naptr->services + 4; /* leading 'e2u+' */ 4.199 + baknaptr.len = naptr->services_len - 4; 4.200 + for (;;) { /* iterate over services in NAPTR */ 4.201 + bakservice.s = service->s + 1; /* leading '+' */ 4.202 + bakservice.len = service->len - 1; 4.203 + naptrlen = findchr(baknaptr.s,'+',baknaptr.len); 4.204 + 4.205 + for (;;) { /* iterate over services in enum_query */ 4.206 + len = findchr(bakservice.s,'+',bakservice.len); 4.207 + if ((naptrlen == len ) && !strncasecmp(baknaptr.s, bakservice.s, len)){ 4.208 + return 1; 4.209 + } 4.210 + if ( (bakservice.len -= len+1) > 0) { 4.211 + bakservice.s += len+1; 4.212 + continue; 4.213 + } 4.214 + break; 4.215 + } 4.216 + if ( (baknaptr.len -= naptrlen+1) > 0) { 4.217 + baknaptr.s += naptrlen+1; 4.218 + continue; 4.219 + } 4.220 + break; 4.221 + } 4.222 + /* no matching service found */ 4.223 + return 0; 4.224 + } 4.225 +} 4.226 + 4.227 + 4.228 +/* 4.229 + * Checks if argument is an e164 number starting with + 4.230 + */ 4.231 +static inline int is_e164(str* _user) 4.232 +{ 4.233 + int i; 4.234 + char c; 4.235 + 4.236 + if ((_user->len > 2) && (_user->len < 17) && ((_user->s)[0] == '+')) { 4.237 + for (i = 1; i < _user->len; i++) { 4.238 + c = (_user->s)[i]; 4.239 + if ((c < '0') || (c > '9')) return -1; 4.240 + } 4.241 + return 1; 4.242 + } else { 4.243 + return -1; 4.244 + } 4.245 +} 4.246 + 4.247 + 4.248 +/* 4.249 + * Call is_from_user_enum_2 with module parameter suffix and default service. 4.250 + */ 4.251 +int is_from_user_enum_0(struct sip_msg* _msg, char* _str1, char* _str2) 4.252 +{ 4.253 + return is_from_user_enum_2(_msg, (char *)(&suffix), (char *)(&service)); 4.254 +} 4.255 + 4.256 +/* 4.257 + * Call is_from_user_enum_2 with given suffix and default service. 4.258 + */ 4.259 +int is_from_user_enum_1(struct sip_msg* _msg, char* _suffix, char* _str2) 4.260 +{ 4.261 + return is_from_user_enum_2(_msg, _suffix, (char *)(&service)); 4.262 +} 4.263 + 4.264 +/* 4.265 + * Check if from user is a valid enum based user, and check to make sure 4.266 + * that the src_ip == an srv record that maps to the enum from user. 4.267 + */ 4.268 +int is_from_user_enum_2(struct sip_msg* _msg, char* _suffix, char* _service) 4.269 +{ 4.270 + struct ip_addr addr; 4.271 + struct hostent* he; 4.272 + unsigned short zp; 4.273 + unsigned short proto; 4.274 + char *user_s; 4.275 + int user_len, i, j; 4.276 + char name[MAX_DOMAIN_SIZE]; 4.277 + char uri[MAX_URI_SIZE]; 4.278 + struct sip_uri *furi; 4.279 + struct sip_uri luri; 4.280 + struct rdata* head; 4.281 + 4.282 + str* suffix; 4.283 + str* service; 4.284 + 4.285 + struct rdata* l; 4.286 + struct naptr_rdata* naptr; 4.287 + 4.288 + str pattern, replacement, result; 4.289 + char string[17]; 4.290 + 4.291 + if (parse_from_header(_msg) < 0) { 4.292 + LM_ERR("Failed to parse From header\n"); 4.293 + return -1; 4.294 + } 4.295 + 4.296 + if(_msg->from==NULL || get_from(_msg)==NULL) { 4.297 + LM_DBG("No From header\n"); 4.298 + return -1; 4.299 + } 4.300 + 4.301 + if ((furi = parse_from_uri(_msg)) == NULL) { 4.302 + LM_ERR("Failed to parse From URI\n"); 4.303 + return -1; 4.304 + } 4.305 + 4.306 + suffix = (str*)_suffix; 4.307 + service = (str*)_service; 4.308 + 4.309 + if (is_e164(&(furi->user)) == -1) { 4.310 + LM_ERR("From URI user is not an E164 number\n"); 4.311 + return -1; 4.312 + } 4.313 + 4.314 + /* assert: the from user is a valid formatted e164 string */ 4.315 + 4.316 + user_s = furi->user.s; 4.317 + user_len = furi->user.len; 4.318 + 4.319 + j = 0; 4.320 + for (i = user_len - 1; i > 0; i--) { 4.321 + name[j] = user_s[i]; 4.322 + name[j + 1] = '.'; 4.323 + j = j + 2; 4.324 + } 4.325 + 4.326 + memcpy(name + j, suffix->s, suffix->len + 1); 4.327 + 4.328 + head = get_record(name, T_NAPTR); 4.329 + 4.330 + if (head == 0) { 4.331 + LM_DBG("No NAPTR record found for %s.\n", name); 4.332 + return -3; 4.333 + } 4.334 + 4.335 + /* we have the naptr records, loop and find an srv record with */ 4.336 + /* same ip address as source ip address, if we do then true is returned */ 4.337 + 4.338 + for (l = head; l; l = l->next) { 4.339 + 4.340 + if (l->type != T_NAPTR) continue; /*should never happen*/ 4.341 + naptr = (struct naptr_rdata*)l->rdata; 4.342 + if (naptr == 0) { 4.343 + LM_ERR("Null rdata in DNS response\n"); 4.344 + free_rdata_list(head); 4.345 + return -4; 4.346 + } 4.347 + 4.348 + LM_DBG("ENUM query on %s: order %u, pref %u, flen %u, flags " 4.349 + "'%.*s', slen %u, services '%.*s', rlen %u, " 4.350 + "regexp '%.*s'\n", 4.351 + name, naptr->order, naptr->pref, 4.352 + naptr->flags_len, (int)(naptr->flags_len), ZSW(naptr->flags), naptr->services_len, 4.353 + (int)(naptr->services_len), ZSW(naptr->services), naptr->regexp_len, 4.354 + (int)(naptr->regexp_len), ZSW(naptr->regexp)); 4.355 + 4.356 + if (sip_match(naptr, service) != 0) { 4.357 + if (parse_naptr_regexp(&(naptr->regexp[0]), naptr->regexp_len, 4.358 + &pattern, &replacement) < 0) { 4.359 + free_rdata_list(head); /*clean up*/ 4.360 + LM_ERR("Parsing of NAPTR regexp failed\n"); 4.361 + return -5; 4.362 + } 4.363 +#ifdef LATER 4.364 + if ((pattern.len == 4) && (strncmp(pattern.s, "^.*$", 4) == 0)) { 4.365 + LM_DBG("Resulted in replacement: '%.*s'\n", 4.366 + replacement.len, ZSW(replacement.s)); 4.367 + retval = set_uri(_msg, replacement.s, replacement.len); 4.368 + free_rdata_list(head); /*clean up*/ 4.369 + return retval; 4.370 + } 4.371 +#endif 4.372 + result.s = &(uri[0]); 4.373 + result.len = MAX_URI_SIZE; 4.374 + /* Avoid making copies of pattern and replacement */ 4.375 + pattern.s[pattern.len] = (char)0; 4.376 + replacement.s[replacement.len] = (char)0; 4.377 + /* We have already checked the size of 4.378 + _msg->parsed_uri.user.s */ 4.379 + memcpy(&(string[0]), user_s, user_len); 4.380 + string[user_len] = (char)0; 4.381 + if (reg_replace(pattern.s, replacement.s, &(string[0]), 4.382 + &result) < 0) { 4.383 + pattern.s[pattern.len] = '!'; 4.384 + replacement.s[replacement.len] = '!'; 4.385 + LM_ERR("Regexp replace failed\n"); 4.386 + free_rdata_list(head); /*clean up*/ 4.387 + return -6; 4.388 + } 4.389 + LM_DBG("Resulted in replacement: '%.*s'\n", 4.390 + result.len, ZSW(result.s)); 4.391 + 4.392 + if(parse_uri(result.s, result.len, &luri) < 0) 4.393 + { 4.394 + LM_ERR("Parsing of URI <%.*s> failed\n", 4.395 + result.len, result.s); 4.396 + free_rdata_list(head); /*clean up*/ 4.397 + return -7; 4.398 + } 4.399 + 4.400 + pattern.s[pattern.len] = '!'; 4.401 + replacement.s[replacement.len] = '!'; 4.402 + 4.403 + zp = 0; 4.404 + proto = PROTO_NONE; 4.405 + he = sip_resolvehost(&luri.host, &zp, &proto, 4.406 + (luri.type==SIPS_URI_T)?1:0 , 0); 4.407 + 4.408 + hostent2ip_addr(&addr, he, 0); 4.409 + 4.410 + if(ip_addr_cmp(&addr, &_msg->rcv.src_ip)) 4.411 + { 4.412 + free_rdata_list(head); 4.413 + return(1); 4.414 + } 4.415 + } 4.416 + } 4.417 + free_rdata_list(head); /*clean up*/ 4.418 + LM_DBG("FAIL\n"); 4.419 + 4.420 + /* must not have found the record */ 4.421 + return(-8); 4.422 +} 4.423 + 4.424 + 4.425 + 4.426 +/* 4.427 + * Add parameter to URI. 4.428 + */ 4.429 +int add_uri_param(str *uri, str *param, str *new_uri) 4.430 +{ 4.431 + struct sip_uri puri; 4.432 + char *at; 4.433 + 4.434 + if (parse_uri(uri->s, uri->len, &puri) < 0) { 4.435 + return 0; 4.436 + } 4.437 + 4.438 + /* if current uri has no headers, pad param to the end of uri */ 4.439 + if (puri.headers.len == 0) { 4.440 + memcpy(uri->s + uri->len, param->s, param->len); 4.441 + uri->len = uri->len + param->len; 4.442 + new_uri->len = 0; 4.443 + return 1; 4.444 + } 4.445 + 4.446 + /* otherwise take the long path and create new_uri */ 4.447 + at = new_uri->s; 4.448 + switch (puri.type) { 4.449 + case SIP_URI_T: 4.450 + memcpy(at, "sip:", 4); 4.451 + at = at + 4; 4.452 + break; 4.453 + case SIPS_URI_T: 4.454 + memcpy(at, "sips:", 5); 4.455 + at = at + 5; 4.456 + break; 4.457 + case TEL_URI_T: 4.458 + memcpy(at, "tel:", 4); 4.459 + at = at + 4; 4.460 + break; 4.461 + case TELS_URI_T: 4.462 + memcpy(at, "tels:", 5); 4.463 + at = at + 5; 4.464 + break; 4.465 + default: 4.466 + LM_ERR("Unknown URI scheme <%d>\n", puri.type); 4.467 + return 0; 4.468 + } 4.469 + if (puri.user.len) { 4.470 + memcpy(at, puri.user.s, puri.user.len); 4.471 + at = at + puri.user.len; 4.472 + if (puri.passwd.len) { 4.473 + *at = ':'; 4.474 + at = at + 1; 4.475 + memcpy(at, puri.passwd.s, puri.passwd.len); 4.476 + at = at + puri.passwd.len; 4.477 + }; 4.478 + *at = '@'; 4.479 + at = at + 1; 4.480 + } 4.481 + memcpy(at, puri.host.s, puri.host.len); 4.482 + at = at + puri.host.len; 4.483 + if (puri.port.len) { 4.484 + *at = ':'; 4.485 + at = at + 1; 4.486 + memcpy(at, puri.port.s, puri.port.len); 4.487 + at = at + puri.port.len; 4.488 + } 4.489 + if (puri.params.len) { 4.490 + *at = ';'; 4.491 + at = at + 1; 4.492 + memcpy(at, puri.params.s, puri.params.len); 4.493 + at = at + puri.params.len; 4.494 + } 4.495 + memcpy(at, param->s, param->len); 4.496 + at = at + param->len; 4.497 + *at = '?'; 4.498 + at = at + 1; 4.499 + memcpy(at, puri.headers.s, puri.headers.len); 4.500 + at = at + puri.headers.len; 4.501 + new_uri->len = at - new_uri->s; 4.502 + return 1; 4.503 +} 4.504 + 4.505 +/* 4.506 + * Tests if one result record is "greater" that the other. Non-NAPTR records 4.507 + * greater that NAPTR record. An invalid NAPTR record is greater than a 4.508 + * valid one. Valid NAPTR records are compared based on their 4.509 + * (order,preference). 4.510 + */ 4.511 +static inline int naptr_greater(struct rdata* a, struct rdata* b) 4.512 +{ 4.513 + struct naptr_rdata *na, *nb; 4.514 + 4.515 + if (a->type != T_NAPTR) return 1; 4.516 + if (b->type != T_NAPTR) return 0; 4.517 + 4.518 + na = (struct naptr_rdata*)a->rdata; 4.519 + if (na == 0) return 1; 4.520 + 4.521 + nb = (struct naptr_rdata*)b->rdata; 4.522 + if (nb == 0) return 0; 4.523 + 4.524 + return (((na->order) << 16) + na->pref) > 4.525 + (((nb->order) << 16) + nb->pref); 4.526 +} 4.527 + 4.528 + 4.529 +/* 4.530 + * Bubble sorts result record list according to naptr (order,preference). 4.531 + */ 4.532 +static inline void naptr_sort(struct rdata** head) 4.533 +{ 4.534 + struct rdata *p, *q, *r, *s, *temp, *start; 4.535 + 4.536 + /* r precedes p and s points to the node up to which comparisons 4.537 + are to be made */ 4.538 + 4.539 + s = NULL; 4.540 + start = *head; 4.541 + while ( s != start -> next ) { 4.542 + r = p = start ; 4.543 + q = p -> next ; 4.544 + while ( p != s ) { 4.545 + if ( naptr_greater(p, q) ) { 4.546 + if ( p == start ) { 4.547 + temp = q -> next ; 4.548 + q -> next = p ; 4.549 + p -> next = temp ; 4.550 + start = q ; 4.551 + r = q ; 4.552 + } else { 4.553 + temp = q -> next ; 4.554 + q -> next = p ; 4.555 + p -> next = temp ; 4.556 + r -> next = q ; 4.557 + r = q ; 4.558 + } 4.559 + } else { 4.560 + r = p ; 4.561 + p = p -> next ; 4.562 + } 4.563 + q = p -> next ; 4.564 + if ( q == s ) s = p ; 4.565 + } 4.566 + } 4.567 + *head = start; 4.568 +} 4.569 + 4.570 + 4.571 +/* 4.572 + * Makes enum query on name. On success, rewrites user part and 4.573 + * replaces Request-URI. 4.574 + */ 4.575 +int do_query(struct sip_msg* _msg, char *user, char *name, str *service) { 4.576 + 4.577 + char uri[MAX_URI_SIZE]; 4.578 + char new_uri[MAX_URI_SIZE]; 4.579 + unsigned int priority, curr_prio, first; 4.580 + qvalue_t q; 4.581 + struct rdata* head; 4.582 + struct rdata* l; 4.583 + struct naptr_rdata* naptr; 4.584 + str pattern, replacement, result, new_result; 4.585 + 4.586 + head = get_record(name, T_NAPTR); 4.587 + 4.588 + if (head == 0) { 4.589 + LM_DBG("No NAPTR record found for %s.\n", name); 4.590 + return -1; 4.591 + } 4.592 + 4.593 + naptr_sort(&head); 4.594 + 4.595 + q = MAX_Q - 10; 4.596 + curr_prio = 0; 4.597 + first = 1; 4.598 + 4.599 + for (l = head; l; l = l->next) { 4.600 + 4.601 + if (l->type != T_NAPTR) continue; /*should never happen*/ 4.602 + naptr = (struct naptr_rdata*)l->rdata; 4.603 + if (naptr == 0) { 4.604 + LM_ERR("Null rdata in DNS response\n"); 4.605 + continue; 4.606 + } 4.607 + 4.608 + LM_DBG("ENUM query on %s: order %u, pref %u, flen %u, flags '%.*s', " 4.609 + "slen %u, services '%.*s', rlen %u, regexp '%.*s'\n", 4.610 + name, naptr->order, naptr->pref, 4.611 + naptr->flags_len, (int)(naptr->flags_len), ZSW(naptr->flags), 4.612 + naptr->services_len, 4.613 + (int)(naptr->services_len), ZSW(naptr->services), naptr->regexp_len, 4.614 + (int)(naptr->regexp_len), ZSW(naptr->regexp)); 4.615 + 4.616 + if (sip_match(naptr, service) == 0) continue; 4.617 + 4.618 + if (parse_naptr_regexp(&(naptr->regexp[0]), naptr->regexp_len, 4.619 + &pattern, &replacement) < 0) { 4.620 + LM_ERR("Parsing of NAPTR regexp failed\n"); 4.621 + continue; 4.622 + } 4.623 + result.s = &(uri[0]); 4.624 + result.len = MAX_URI_SIZE; 4.625 + /* Avoid making copies of pattern and replacement */ 4.626 + pattern.s[pattern.len] = (char)0; 4.627 + replacement.s[replacement.len] = (char)0; 4.628 + if (reg_replace(pattern.s, replacement.s, user, &result) < 0) { 4.629 + pattern.s[pattern.len] = '!'; 4.630 + replacement.s[replacement.len] = '!'; 4.631 + LM_ERR("Regexp replace failed\n"); 4.632 + continue; 4.633 + } 4.634 + LM_DBG("Resulted in replacement: '%.*s'\n", result.len, ZSW(result.s)); 4.635 + pattern.s[pattern.len] = '!'; 4.636 + replacement.s[replacement.len] = '!'; 4.637 + 4.638 + if (param.len > 0) { 4.639 + if (result.len + param.len > MAX_URI_SIZE - 1) { 4.640 + LM_ERR("URI is too long\n"); 4.641 + continue; 4.642 + } 4.643 + new_result.s = &(new_uri[0]); 4.644 + new_result.len = MAX_URI_SIZE; 4.645 + if (add_uri_param(&result, ¶m, &new_result) == 0) { 4.646 + LM_ERR("Parsing of URI <%.*s> failed\n", 4.647 + result.len, result.s); 4.648 + continue; 4.649 + } 4.650 + if (new_result.len > 0) { 4.651 + result = new_result; 4.652 + } 4.653 + } 4.654 + 4.655 + if (first) { 4.656 + if (set_ruri(_msg, &result) == -1) { 4.657 + goto done; 4.658 + } 4.659 + set_ruri_q(q); 4.660 + first = 0; 4.661 + curr_prio = ((naptr->order) << 16) + naptr->pref; 4.662 + } else { 4.663 + priority = ((naptr->order) << 16) + naptr->pref; 4.664 + if (priority > curr_prio) { 4.665 + q = q - 10; 4.666 + curr_prio = priority; 4.667 + } 4.668 + if (append_branch(_msg, &result, 0, 0, q, 0, 0) == -1) { 4.669 + goto done; 4.670 + } 4.671 + } 4.672 + } 4.673 + 4.674 +done: 4.675 + free_rdata_list(head); 4.676 + return first ? -1 : 1; 4.677 +} 4.678 + 4.679 + 4.680 +/* 4.681 + * Call enum_query_2 with module parameter suffix and default service. 4.682 + */ 4.683 +int enum_query_0(struct sip_msg* _msg, char* _str1, char* _str2) 4.684 +{ 4.685 + return enum_query_2(_msg, (char *)(&suffix), (char *)(&service)); 4.686 +} 4.687 + 4.688 + 4.689 +/* 4.690 + * Call enum_query_2 with given suffix and default service. 4.691 + */ 4.692 +int enum_query_1(struct sip_msg* _msg, char* _suffix, char* _str2) 4.693 +{ 4.694 + return enum_query_2(_msg, _suffix, (char *)(&service)); 4.695 +} 4.696 + 4.697 + 4.698 +/* 4.699 + * See documentation in README file. 4.700 + */ 4.701 +int enum_query_2(struct sip_msg* _msg, char* _suffix, char* _service) 4.702 +{ 4.703 + char *user_s; 4.704 + int user_len, i, j; 4.705 + char name[MAX_DOMAIN_SIZE]; 4.706 + char string[17]; 4.707 + 4.708 + str *suffix, *service; 4.709 + 4.710 + suffix = (str*)_suffix; 4.711 + service = (str*)_service; 4.712 + 4.713 + if (parse_sip_msg_uri(_msg) < 0) { 4.714 + LM_ERR("Parsing of R-URI failed\n"); 4.715 + return -1; 4.716 + } 4.717 + 4.718 + if (is_e164(&(_msg->parsed_uri.user)) == -1) { 4.719 + LM_ERR("R-URI user is not an E164 number\n"); 4.720 + return -1; 4.721 + } 4.722 + 4.723 + user_s = _msg->parsed_uri.user.s; 4.724 + user_len = _msg->parsed_uri.user.len; 4.725 + 4.726 + memcpy(&(string[0]), user_s, user_len); 4.727 + string[user_len] = (char)0; 4.728 + 4.729 + j = 0; 4.730 + for (i = user_len - 1; i > 0; i--) { 4.731 + name[j] = user_s[i]; 4.732 + name[j + 1] = '.'; 4.733 + j = j + 2; 4.734 + } 4.735 + 4.736 + memcpy(name + j, suffix->s, suffix->len + 1); 4.737 + 4.738 + return do_query(_msg, string, name, service); 4.739 +} 4.740 + 4.741 + 4.742 +/*********** INFRASTRUCTURE ENUM ***************/ 4.743 + 4.744 +/* 4.745 + * Call enum_query_2 with default suffix and service. 4.746 + */ 4.747 +int i_enum_query_0(struct sip_msg* _msg, char* _suffix, char* _service) 4.748 +{ 4.749 + return i_enum_query_2(_msg, (char *)(&i_suffix), (char *)(&service)); 4.750 +} 4.751 + 4.752 +/* 4.753 + * Call enum_query_2 with given suffix and default service. 4.754 + */ 4.755 +int i_enum_query_1(struct sip_msg* _msg, char* _suffix, char* _service) 4.756 +{ 4.757 + return i_enum_query_2(_msg, _suffix, (char *)(&service)); 4.758 +} 4.759 + 4.760 + 4.761 +int i_enum_query_2(struct sip_msg* _msg, char* _suffix, char* _service) 4.762 +{ 4.763 + char *user_s; 4.764 + int user_len, i, j; 4.765 + char name[MAX_DOMAIN_SIZE]; 4.766 + char apex[MAX_COMPONENT_SIZE + 1]; 4.767 + char separator[MAX_COMPONENT_SIZE + 1]; 4.768 + int sdl = 0; /* subdomain location: infrastructure enum offset */ 4.769 + int cc_len; 4.770 + struct rdata* head; 4.771 + 4.772 + char string[17]; 4.773 + 4.774 + str *suffix, *service; 4.775 + 4.776 + suffix = (str*)_suffix; 4.777 + service = (str*)_service; 4.778 + 4.779 + if (parse_sip_msg_uri(_msg) < 0) { 4.780 + LM_ERR("Parsing of R-URI failed\n"); 4.781 + return -1; 4.782 + } 4.783 + 4.784 + if (is_e164(&(_msg->parsed_uri.user)) == -1) { 4.785 + LM_ERR("R-URI user is not an E164 number\n"); 4.786 + return -1; 4.787 + } 4.788 + 4.789 + user_s = _msg->parsed_uri.user.s; 4.790 + user_len = _msg->parsed_uri.user.len; 4.791 + 4.792 + /* make sure we don't run out of space in strings */ 4.793 + if (( 2*user_len + MAX_COMPONENT_SIZE + MAX_COMPONENT_SIZE + 4) > MAX_DOMAIN_SIZE) { 4.794 + LM_ERR("Strings too long\n"); 4.795 + return -1; 4.796 + } 4.797 + if ( i_branchlabel.len > MAX_COMPONENT_SIZE ) { 4.798 + LM_ERR("i_branchlabel too long\n"); 4.799 + return -1; 4.800 + } 4.801 + if ( suffix->len > MAX_COMPONENT_SIZE ) { 4.802 + LM_ERR("Suffix too long\n"); 4.803 + return -1; 4.804 + } 4.805 + 4.806 + 4.807 + memcpy(&(string[0]), user_s, user_len); 4.808 + string[user_len] = (char)0; 4.809 + 4.810 + /* Set up parameters as for user-enum */ 4.811 + memcpy(apex, suffix->s , suffix->len); 4.812 + apex[suffix->len] = (char)0; 4.813 + sdl = 0; /* where to insert i-enum separator */ 4.814 + separator[0] = 0; /* don't insert anything */ 4.815 + 4.816 + cc_len = cclen(string + 1); 4.817 + 4.818 + if (!strncasecmp(i_bl_alg.s,"ebl",i_bl_alg.len)) { 4.819 + sdl = cc_len; /* default */ 4.820 + 4.821 + j = 0; 4.822 + memcpy(name, i_branchlabel.s, i_branchlabel.len); 4.823 + j += i_branchlabel.len; 4.824 + name[j++] = '.'; 4.825 + 4.826 + for (i = cc_len ; i > 0; i--) { 4.827 + name[j++] = user_s[i]; 4.828 + name[j++] = '.'; 4.829 + } 4.830 + memcpy(name + j, suffix->s, suffix->len + 1); 4.831 + 4.832 + LM_DBG("Looking for EBL record for %s.\n", name); 4.833 + head = get_record(name, T_EBL); 4.834 + if (head == 0) { 4.835 + LM_DBG("No EBL found for %s. Defaulting to user ENUM.\n",name); 4.836 + } else { 4.837 + struct ebl_rdata* ebl; 4.838 + ebl = (struct ebl_rdata *) head->rdata; 4.839 + 4.840 + LM_DBG("EBL record for %s is %d / %.*s / %.*s.\n", 4.841 + name, ebl->position, (int)ebl->separator_len, 4.842 + ebl->separator,(int)ebl->apex_len, ebl->apex); 4.843 + 4.844 + if ((ebl->apex_len > MAX_COMPONENT_SIZE) || (ebl->separator_len > MAX_COMPONENT_SIZE)) { 4.845 + LM_ERR("EBL strings too long\n"); 4.846 + return -1; 4.847 + } 4.848 + 4.849 + if (ebl->position > 15) { 4.850 + LM_ERR("EBL position too large (%d)\n", 4.851 + ebl->position); 4.852 + return -1; 4.853 + } 4.854 + 4.855 + sdl = ebl->position; 4.856 + 4.857 + memcpy(separator, ebl->separator, ebl->separator_len); 4.858 + separator[ebl->separator_len] = 0; 4.859 + 4.860 + memcpy(apex, ebl->apex, ebl->apex_len); 4.861 + apex[ebl->apex_len] = 0; 4.862 + free_rdata_list(head); 4.863 + } 4.864 + } else if (!strncasecmp(i_bl_alg.s,"txt",i_bl_alg.len)) { 4.865 + sdl = cc_len; /* default */ 4.866 + memcpy(separator, i_branchlabel.s, i_branchlabel.len); 4.867 + separator[i_branchlabel.len] = 0; 4.868 + /* no change to apex */ 4.869 + 4.870 + j = 0; 4.871 + memcpy(name, i_branchlabel.s, i_branchlabel.len); 4.872 + j += i_branchlabel.len; 4.873 + name[j++] = '.'; 4.874 + 4.875 + for (i = cc_len ; i > 0; i--) { 4.876 + name[j++] = user_s[i]; 4.877 + name[j++] = '.'; 4.878 + } 4.879 + memcpy(name + j, suffix->s, suffix->len + 1); 4.880 + 4.881 + head = get_record(name, T_TXT); 4.882 + if (head == 0) { 4.883 + LM_DBG("TXT found for %s. Defaulting to %d\n", 4.884 + name, cc_len); 4.885 + } else { 4.886 + sdl = atoi(((struct txt_rdata*)head->rdata)->txt); 4.887 + LM_DBG("TXT record for %s is %d.\n", name, sdl); 4.888 + 4.889 + if ((sdl < 0) || (sdl > 10)) { 4.890 + LM_ERR("Sdl %d out of bounds. Set back to cc_len.\n", sdl); 4.891 + sdl = cc_len; 4.892 + } 4.893 + free_rdata_list(head); 4.894 + } 4.895 + } else { /* defaults to CC */ 4.896 + sdl = cc_len; 4.897 + memcpy(separator, i_branchlabel.s, i_branchlabel.len); 4.898 + separator[i_branchlabel.len] = 0; 4.899 + /* no change to apex */ 4.900 + } 4.901 + 4.902 + j = 0; 4.903 + sdl++; /* to avoid comparing i to (sdl+1) */ 4.904 + for (i = user_len - 1; i > 0; i--) { 4.905 + name[j] = user_s[i]; 4.906 + name[j + 1] = '.'; 4.907 + j = j + 2; 4.908 + if (separator[0] && (i == sdl)) { /* insert the I-ENUM separator here? */ 4.909 + strcpy(name + j, separator); /* we've checked string sizes. */ 4.910 + j += strlen(separator); 4.911 + name[j++] = '.'; 4.912 + } 4.913 + } 4.914 + 4.915 + memcpy(name + j, apex, strlen(apex)+1); 4.916 + 4.917 + return do_query(_msg, string, name, service); 4.918 +} 4.919 + 4.920 + 4.921 + 4.922 +/******************* FQUERY *******************/ 4.923 + 4.924 + 4.925 +/* 4.926 + * Call enum_pv_query_3 with pv arg, module parameter suffix, 4.927 + * and default service. 4.928 + */ 4.929 +int enum_pv_query_1(struct sip_msg* _msg, char* _sp) 4.930 +{ 4.931 + return enum_pv_query_3(_msg, _sp, (char *)(&suffix), (char *)(&service)); 4.932 +} 4.933 + 4.934 +/* 4.935 + * Call enum_pv_query_3 with pv and suffix args and default service. 4.936 + */ 4.937 +int enum_pv_query_2(struct sip_msg* _msg, char* _sp, char* _suffix) 4.938 +{ 4.939 + return enum_pv_query_3(_msg, _sp, _suffix, (char *)(&service)); 4.940 +} 4.941 + 4.942 +/* 4.943 + * See documentation in README file. 4.944 + */ 4.945 + 4.946 +int enum_pv_query_3(struct sip_msg* _msg, char* _sp, char* _suffix, 4.947 + char* _service) 4.948 +{ 4.949 + char *user_s; 4.950 + int user_len, i, j, first; 4.951 + char name[MAX_DOMAIN_SIZE]; 4.952 + char uri[MAX_URI_SIZE]; 4.953 + char new_uri[MAX_URI_SIZE]; 4.954 + unsigned int priority, curr_prio; 4.955 + qvalue_t q; 4.956 + char tostring[17]; 4.957 + struct rdata* head; 4.958 + struct rdata* l; 4.959 + struct naptr_rdata* naptr; 4.960 + str pattern, replacement, result, new_result; 4.961 + str *suffix, *service; 4.962 + char string[17]; 4.963 + pv_spec_t *sp; 4.964 + pv_value_t pv_val; 4.965 + 4.966 + sp = (pv_spec_t *)_sp; 4.967 + suffix = (str*)_suffix; 4.968 + service = (str*)_service; 4.969 + 4.970 + /* 4.971 + * Get R-URI user to tostring 4.972 + */ 4.973 + if (parse_sip_msg_uri(_msg) < 0) { 4.974 + LM_ERR("R-URI parsing failed\n"); 4.975 + return -1; 4.976 + } 4.977 + 4.978 + if (is_e164(&(_msg->parsed_uri.user)) == -1) { 4.979 + LM_ERR("R-URI user is not an E164 number\n"); 4.980 + return -1; 4.981 + } 4.982 + 4.983 + user_s = _msg->parsed_uri.user.s; 4.984 + user_len = _msg->parsed_uri.user.len; 4.985 + 4.986 + memcpy(&(tostring[0]), user_s, user_len); 4.987 + tostring[user_len] = (char)0; 4.988 + 4.989 + /* 4.990 + * Get E.164 number from pseudo variable 4.991 + */ 4.992 + if (sp && (pv_get_spec_value(_msg, sp, &pv_val) == 0)) { 4.993 + if (pv_val.flags & PV_VAL_STR) { 4.994 + if (pv_val.rs.len == 0 || pv_val.rs.s == NULL) { 4.995 + LM_DBG("Missing E.164 number\n"); 4.996 + return -1; 4.997 + } 4.998 + } else { 4.999 + LM_DBG("Pseudo variable value is not string\n"); 4.1000 + return -1; 4.1001 + } 4.1002 + } else { 4.1003 + LM_DBG("Cannot get pseudo variable value\n"); 4.1004 + return -1; 4.1005 + } 4.1006 + if (is_e164(&(pv_val.rs)) == -1) { 4.1007 + LM_ERR("pseudo variable does not contain an E164 number\n"); 4.1008 + return -1; 4.1009 + } 4.1010 + 4.1011 + user_s = pv_val.rs.s; 4.1012 + user_len = pv_val.rs.len; 4.1013 + 4.1014 + memcpy(&(string[0]), user_s, user_len); 4.1015 + string[user_len] = (char)0; 4.1016 + 4.1017 + j = 0; 4.1018 + for (i = user_len - 1; i > 0; i--) { 4.1019 + name[j] = user_s[i]; 4.1020 + name[j + 1] = '.'; 4.1021 + j = j + 2; 4.1022 + } 4.1023 + 4.1024 + memcpy(name + j, suffix->s, suffix->len + 1); 4.1025 + 4.1026 + head = get_record(name, T_NAPTR); 4.1027 + 4.1028 + if (head == 0) { 4.1029 + LM_DBG("No NAPTR record found for %s.\n", name); 4.1030 + return -1; 4.1031 + } 4.1032 + 4.1033 + naptr_sort(&head); 4.1034 + 4.1035 + q = MAX_Q - 10; 4.1036 + curr_prio = 0; 4.1037 + first = 1; 4.1038 + 4.1039 + for (l = head; l; l = l->next) { 4.1040 + 4.1041 + if (l->type != T_NAPTR) continue; /*should never happen*/ 4.1042 + naptr = (struct naptr_rdata*)l->rdata; 4.1043 + if (naptr == 0) { 4.1044 + LM_ERR("Null rdata in DNS response\n"); 4.1045 + continue; 4.1046 + } 4.1047 + 4.1048 + LM_DBG("ENUM query on %s: order %u, pref %u, flen %u, flags " 4.1049 + "'%.*s', slen %u, services '%.*s', rlen %u, " 4.1050 + "regexp '%.*s'\n", 4.1051 + name, naptr->order, naptr->pref, 4.1052 + naptr->flags_len, (int)(naptr->flags_len), ZSW(naptr->flags), 4.1053 + naptr->services_len, 4.1054 + (int)(naptr->services_len), ZSW(naptr->services), naptr->regexp_len, 4.1055 + (int)(naptr->regexp_len), ZSW(naptr->regexp)); 4.1056 + 4.1057 + if (sip_match(naptr, service) == 0) continue; 4.1058 + 4.1059 + if (parse_naptr_regexp(&(naptr->regexp[0]), naptr->regexp_len, 4.1060 + &pattern, &replacement) < 0) { 4.1061 + LM_ERR("Parsing of NAPTR regexp failed\n"); 4.1062 + continue; 4.1063 + } 4.1064 + result.s = &(uri[0]); 4.1065 + result.len = MAX_URI_SIZE; 4.1066 + /* Avoid making copies of pattern and replacement */ 4.1067 + pattern.s[pattern.len] = (char)0; 4.1068 + replacement.s[replacement.len] = (char)0; 4.1069 + if (reg_replace(pattern.s, replacement.s, &(tostring[0]), 4.1070 + &result) < 0) { 4.1071 + pattern.s[pattern.len] = '!'; 4.1072 + replacement.s[replacement.len] = '!'; 4.1073 + LM_ERR("Regexp replace failed\n"); 4.1074 + continue; 4.1075 + } 4.1076 + LM_DBG("Resulted in replacement: '%.*s'\n", 4.1077 + result.len, ZSW(result.s)); 4.1078 + pattern.s[pattern.len] = '!'; 4.1079 + replacement.s[replacement.len] = '!'; 4.1080 + 4.1081 + if (param.len > 0) { 4.1082 + if (result.len + param.len > MAX_URI_SIZE - 1) { 4.1083 + LM_ERR("URI is too long\n"); 4.1084 + continue; 4.1085 + } 4.1086 + new_result.s = &(new_uri[0]); 4.1087 + new_result.len = MAX_URI_SIZE; 4.1088 + if (add_uri_param(&result, ¶m, &new_result) == 0) { 4.1089 + LM_ERR("Parsing of URI <%.*s> failed\n", 4.1090 + result.len, result.s); 4.1091 + continue; 4.1092 + } 4.1093 + if (new_result.len > 0) { 4.1094 + result = new_result; 4.1095 + } 4.1096 + } 4.1097 + 4.1098 + if (first) { 4.1099 + if (set_ruri(_msg, &result) == -1) { 4.1100 + goto done; 4.1101 + } 4.1102 + set_ruri_q(q); 4.1103 + first = 0; 4.1104 + curr_prio = ((naptr->order) << 16) + naptr->pref; 4.1105 + } else { 4.1106 + priority = ((naptr->order) << 16) + naptr->pref; 4.1107 + if (priority > curr_prio) { 4.1108 + q = q - 10; 4.1109 + curr_prio = priority; 4.1110 + } 4.1111 + if (append_branch(_msg, &result, 0, 0, q, 0, 0) == -1) { 4.1112 + goto done; 4.1113 + } 4.1114 + } 4.1115 + } 4.1116 + 4.1117 +done: 4.1118 + free_rdata_list(head); 4.1119 + return first ? -1 : 1; 4.1120 +} 4.1121 +
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/opensips/modules/enum/enum.h Mon Jan 18 19:47:23 2010 +0100 5.3 @@ -0,0 +1,70 @@ 5.4 +/* 5.5 + * $Id: enum.h 5901 2009-07-21 07:45:05Z bogdan_iancu $ 5.6 + * 5.7 + * Header file for Enum and E164 related functions 5.8 + * 5.9 + * Copyright (C) 2002-2008 Juha Heinanen 5.10 + * 5.11 + * This file is part of opensips, a free SIP server. 5.12 + * 5.13 + * opensips is free software; you can redistribute it and/or modify 5.14 + * it under the terms of the GNU General Public License as published by 5.15 + * the Free Software Foundation; either version 2 of the License, or 5.16 + * (at your option) any later version 5.17 + * 5.18 + * opensips is distributed in the hope that it will be useful, 5.19 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 5.20 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 5.21 + * GNU General Public License for more details. 5.22 + * 5.23 + * You should have received a copy of the GNU General Public License 5.24 + * along with this program; if not, write to the Free Software 5.25 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 5.26 + */ 5.27 + 5.28 + 5.29 +#ifndef ENUM_H 5.30 +#define ENUM_H 5.31 + 5.32 + 5.33 +#include "../../parser/msg_parser.h" 5.34 + 5.35 + 5.36 +#define MAX_DOMAIN_SIZE 256 5.37 +#define MAX_COMPONENT_SIZE 32 /* separator, apex, ... This simplifies checks */ 5.38 + 5.39 + 5.40 +/* 5.41 + * Check if from user is an e164 number and has a naptr record 5.42 + */ 5.43 +int is_from_user_enum_0(struct sip_msg* _msg, char* _str1, char* _str2); 5.44 +int is_from_user_enum_1(struct sip_msg* _msg, char* _suffix, char* _str2); 5.45 +int is_from_user_enum_2(struct sip_msg* _msg, char* _suffix, char* _service); 5.46 + 5.47 +/* 5.48 + * do source number destination routing. 5.49 + * that is, make the ruri based on the from number 5.50 + * this is like source ip policy routing 5.51 + */ 5.52 +int enum_pv_query_1(struct sip_msg* _msg, char* _sp); 5.53 +int enum_pv_query_2(struct sip_msg* _msg, char* _sp, char* _suffix); 5.54 +int enum_pv_query_3(struct sip_msg* _msg, char* _sp, char* _suffix, 5.55 + char* _service); 5.56 + 5.57 +/* 5.58 + * Make enum query and if query succeeds, replace current uri with the 5.59 + * result of the query 5.60 + */ 5.61 +int enum_query_0(struct sip_msg* _msg, char* _str1, char* _str2); 5.62 +int enum_query_1(struct sip_msg* _msg, char* _suffix, char* _str2); 5.63 +int enum_query_2(struct sip_msg* _msg, char* _suffix, char* _service); 5.64 + 5.65 +/* 5.66 + * Infrastructure ENUM versions. 5.67 + */ 5.68 +int i_enum_query_0(struct sip_msg* _msg, char* _str1, char* _str2); 5.69 +int i_enum_query_1(struct sip_msg* _msg, char* _suffix, char* _str2); 5.70 +int i_enum_query_2(struct sip_msg* _msg, char* _suffix, char* _service); 5.71 + 5.72 + 5.73 +#endif /* ENUM_H */
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 6.2 +++ b/opensips/modules/enum/enum_mod.c Mon Jan 18 19:47:23 2010 +0100 6.3 @@ -0,0 +1,157 @@ 6.4 +/* 6.5 + * $Id: enum_mod.c 5976 2009-08-18 13:35:23Z bogdan_iancu $ 6.6 + * 6.7 + * Enum module 6.8 + * 6.9 + * Copyright (C) 2002-2008 Juha Heinanen 6.10 + * 6.11 + * This file is part of opensips, a free SIP server. 6.12 + * 6.13 + * opensips is free software; you can redistribute it and/or modify 6.14 + * it under the terms of the GNU General Public License as published by 6.15 + * the Free Software Foundation; either version 2 of the License, or 6.16 + * (at your option) any later version 6.17 + * 6.18 + * opensips is distributed in the hope that it will be useful, 6.19 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 6.20 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 6.21 + * GNU General Public License for more details. 6.22 + * 6.23 + * You should have received a copy of the GNU General Public License 6.24 + * along with this program; if not, write to the Free Software 6.25 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 6.26 + * 6.27 + * History: 6.28 + * ------- 6.29 + * 2003-03-11: New module interface (janakj) 6.30 + * 2003-03-16: flags export parameter added (janakj) 6.31 + * 2003-12-15: added suffix parameter to enum_query (jh) 6.32 + */ 6.33 + 6.34 + 6.35 +#include "enum_mod.h" 6.36 +#include <stdio.h> 6.37 +#include <stdlib.h> 6.38 +#include "../../sr_module.h" 6.39 +#include "../../error.h" 6.40 +#include "../../mod_fix.h" 6.41 +#include "enum.h" 6.42 + 6.43 + 6.44 + 6.45 +/* 6.46 + * Module initialization function prototype 6.47 + */ 6.48 +static int mod_init(void); 6.49 + 6.50 + 6.51 +/* 6.52 + * Module parameter variables 6.53 + */ 6.54 +char* domain_suffix = "e164.arpa."; 6.55 +char* tel_uri_params = ""; 6.56 + 6.57 +char* branchlabel = "i"; 6.58 +char* i_enum_suffix = "e164.arpa."; 6.59 +char* bl_algorithm = "cc"; 6.60 + 6.61 + 6.62 +/* 6.63 + * Internal module variables 6.64 + */ 6.65 +str suffix; 6.66 +str param; 6.67 +str service; 6.68 + 6.69 +str i_suffix; 6.70 +str i_branchlabel; 6.71 +str i_bl_alg; 6.72 + 6.73 + 6.74 +/* 6.75 + * Exported functions 6.76 + */ 6.77 +static cmd_export_t cmds[] = { 6.78 + {"enum_query", (cmd_function)enum_query_0, 0, 0, 0, REQUEST_ROUTE}, 6.79 + {"enum_query", (cmd_function)enum_query_1, 1, fixup_str_null, 6.80 + fixup_free_str_null, REQUEST_ROUTE}, 6.81 + {"enum_query", (cmd_function)enum_query_2, 2, fixup_str_str, 6.82 + fixup_free_str_str, REQUEST_ROUTE}, 6.83 + {"enum_pv_query", (cmd_function)enum_pv_query_1, 1, fixup_pvar_null, 6.84 + fixup_free_pvar_null, REQUEST_ROUTE}, 6.85 + {"enum_pv_query", (cmd_function)enum_pv_query_2, 2, fixup_pvar_str, 6.86 + fixup_free_pvar_str, REQUEST_ROUTE}, 6.87 + {"enum_pv_query", (cmd_function)enum_pv_query_3, 3, 6.88 + fixup_pvar_str_str, fixup_free_pvar_str_str, REQUEST_ROUTE}, 6.89 + {"is_from_user_enum", (cmd_function)is_from_user_enum_0, 0, 0, 0, 6.90 + REQUEST_ROUTE}, 6.91 + {"is_from_user_enum", (cmd_function)is_from_user_enum_1, 1, 6.92 + fixup_str_null, fixup_free_str_null, REQUEST_ROUTE}, 6.93 + {"is_from_user_enum", (cmd_function)is_from_user_enum_2, 2, 6.94 + fixup_str_str, fixup_free_str_str, REQUEST_ROUTE}, 6.95 + {"i_enum_query", (cmd_function)i_enum_query_0, 0, 0, 0, REQUEST_ROUTE}, 6.96 + {"i_enum_query", (cmd_function)i_enum_query_1, 1, fixup_str_null, 0, 6.97 + REQUEST_ROUTE}, 6.98 + {"i_enum_query", (cmd_function)i_enum_query_2, 2, fixup_str_str, 0, 6.99 + REQUEST_ROUTE}, 6.100 + {0, 0, 0, 0, 0, 0} 6.101 +}; 6.102 + 6.103 + 6.104 +/* 6.105 + * Exported parameters 6.106 + */ 6.107 +static param_export_t params[] = { 6.108 + {"domain_suffix", STR_PARAM, &domain_suffix}, 6.109 + {"tel_uri_params", STR_PARAM, &tel_uri_params}, 6.110 + {"branchlabel", STR_PARAM, &branchlabel}, 6.111 + {"i_enum_suffix", STR_PARAM, &i_enum_suffix}, 6.112 + {"bl_algorithm", STR_PARAM, &bl_algorithm}, 6.113 + {0, 0, 0} 6.114 +}; 6.115 + 6.116 + 6.117 +/* 6.118 + * Module parameter variables 6.119 + */ 6.120 +struct module_exports exports = { 6.121 + "enum", 6.122 + MODULE_VERSION, 6.123 + DEFAULT_DLFLAGS, /* dlopen flags */ 6.124 + cmds, /* Exported functions */ 6.125 + params, /* Exported parameters */ 6.126 + 0, /* exported statistics */ 6.127 + 0, /* exported MI functions */ 6.128 + 0, /* exported pseudo-variables */ 6.129 + 0, /* extra processes */ 6.130 + mod_init, /* module initialization function */ 6.131 + 0, /* response function*/ 6.132 + 0, /* destroy function */ 6.133 + 0 /* per-child init function */ 6.134 +}; 6.135 + 6.136 + 6.137 +static int mod_init(void) 6.138 +{ 6.139 + LM_DBG("Initializing\n"); 6.140 + 6.141 + suffix.s = domain_suffix; 6.142 + suffix.len = strlen(suffix.s); 6.143 + 6.144 + param.s = tel_uri_params; 6.145 + param.len = strlen(param.s); 6.146 + 6.147 + service.len = 0; 6.148 + 6.149 + i_suffix.s = i_enum_suffix; 6.150 + i_suffix.len = strlen(i_enum_suffix); 6.151 + 6.152 + i_branchlabel.s = branchlabel; 6.153 + i_branchlabel.len = strlen(branchlabel); 6.154 + 6.155 + i_bl_alg.s = bl_algorithm; 6.156 + i_bl_alg.len = strlen(bl_algorithm); 6.157 + 6.158 + return 0; 6.159 +} 6.160 +
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 7.2 +++ b/opensips/modules/enum/enum_mod.h Mon Jan 18 19:47:23 2010 +0100 7.3 @@ -0,0 +1,45 @@ 7.4 +/* 7.5 + * $Id: enum_mod.h 5901 2009-07-21 07:45:05Z bogdan_iancu $ 7.6 + * 7.7 + * Enum module headers 7.8 + * 7.9 + * Copyright (C) 2002-2003 Juha Heinanen 7.10 + * 7.11 + * This file is part of opensips, a free SIP server. 7.12 + * 7.13 + * opensips is free software; you can redistribute it and/or modify 7.14 + * it under the terms of the GNU General Public License as published by 7.15 + * the Free Software Foundation; either version 2 of the License, or 7.16 + * (at your option) any later version 7.17 + * 7.18 + * opensips is distributed in the hope that it will be useful, 7.19 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 7.20 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 7.21 + * GNU General Public License for more details. 7.22 + * 7.23 + * You should have received a copy of the GNU General Public License 7.24 + * along with this program; if not, write to the Free Software 7.25 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 7.26 + */ 7.27 + 7.28 + 7.29 +#ifndef ENUM_MOD_H 7.30 +#define ENUM_MOD_H 7.31 + 7.32 + 7.33 +#include "../../str.h" 7.34 + 7.35 + 7.36 +/* 7.37 + * Internal module variables 7.38 + */ 7.39 +extern str suffix; /* str version of domain_suffix */ 7.40 +extern str param; /* str version of tel_uri_params */ 7.41 +extern str service; /* default (empty) service */ 7.42 + 7.43 +extern str i_suffix; /* suffix for infrastructure ENUM */ 7.44 +extern str i_branchlabel; /* the label branching off the infrastructure tree */ 7.45 +extern str i_bl_alg; /* how to know where to branch off */ 7.46 + 7.47 + 7.48 +#endif /* ENUM_MOD_H */