Mon, 18 Jan 2010 19:59:51 +0100
Introduce ISN formatting and lookup logic into the ENUM module.
A detailed description of these changes is provided in enum-isn.txt.
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/opensips/enum-isn.diff Mon Jan 18 19:59:51 2010 +0100 1.3 @@ -0,0 +1,502 @@ 1.4 +Index: modules/enum/enum_mod.h 1.5 +diff -Nau modules/enum/enum_mod.h.orig modules/enum/enum_mod.h 1.6 +--- modules/enum/enum_mod.h.orig 2010-01-18 15:54:52.842465412 +0100 1.7 ++++ modules/enum/enum_mod.h 2010-01-18 15:55:20.812190874 +0100 1.8 +@@ -41,5 +41,7 @@ 1.9 + extern str i_branchlabel; /* the label branching off the infrastructure tree */ 1.10 + extern str i_bl_alg; /* how to know where to branch off */ 1.11 + 1.12 ++extern str isnsuffix; /* str version of isn_suffix */ 1.13 ++ 1.14 + 1.15 + #endif /* ENUM_MOD_H */ 1.16 +Index: modules/enum/enum_mod.c 1.17 +diff -Nau modules/enum/enum_mod.c.orig modules/enum/enum_mod.c 1.18 +--- modules/enum/enum_mod.c.orig 2010-01-18 15:52:57.316263519 +0100 1.19 ++++ modules/enum/enum_mod.c 2010-01-18 15:52:42.844229824 +0100 1.20 +@@ -55,6 +55,8 @@ 1.21 + char* i_enum_suffix = "e164.arpa."; 1.22 + char* bl_algorithm = "cc"; 1.23 + 1.24 ++char* isn_suffix = "freenum.org."; 1.25 ++ 1.26 + 1.27 + /* 1.28 + * Internal module variables 1.29 +@@ -67,6 +69,8 @@ 1.30 + str i_branchlabel; 1.31 + str i_bl_alg; 1.32 + 1.33 ++str isnsuffix; 1.34 ++ 1.35 + 1.36 + /* 1.37 + * Exported functions 1.38 +@@ -94,6 +98,11 @@ 1.39 + REQUEST_ROUTE}, 1.40 + {"i_enum_query", (cmd_function)i_enum_query_2, 2, fixup_str_str, 0, 1.41 + REQUEST_ROUTE}, 1.42 ++ {"isn_query", (cmd_function)isn_query_0, 0, 0, 0, REQUEST_ROUTE}, 1.43 ++ {"isn_query", (cmd_function)isn_query_1, 1, fixup_str_null, 1.44 ++ fixup_free_str_null, REQUEST_ROUTE}, 1.45 ++ {"isn_query", (cmd_function)isn_query_2, 2, fixup_str_str, 1.46 ++ fixup_free_str_str, REQUEST_ROUTE}, 1.47 + {0, 0, 0, 0, 0, 0} 1.48 + }; 1.49 + 1.50 +@@ -107,6 +116,7 @@ 1.51 + {"branchlabel", STR_PARAM, &branchlabel}, 1.52 + {"i_enum_suffix", STR_PARAM, &i_enum_suffix}, 1.53 + {"bl_algorithm", STR_PARAM, &bl_algorithm}, 1.54 ++ {"isn_suffix", STR_PARAM, &isn_suffix}, 1.55 + {0, 0, 0} 1.56 + }; 1.57 + 1.58 +@@ -152,6 +162,9 @@ 1.59 + i_bl_alg.s = bl_algorithm; 1.60 + i_bl_alg.len = strlen(bl_algorithm); 1.61 + 1.62 ++ isnsuffix.s = isn_suffix; 1.63 ++ isnsuffix.len = strlen(isn_suffix.s); 1.64 ++ 1.65 + return 0; 1.66 + } 1.67 + 1.68 +Index: modules/enum/enum.h 1.69 +diff -Nau modules/enum/enum.h.orig modules/enum/enum.h 1.70 +--- modules/enum/enum.h.orig 2010-01-18 15:54:40.361624448 +0100 1.71 ++++ modules/enum/enum.h 2010-01-18 15:54:43.090330399 +0100 1.72 +@@ -66,5 +66,13 @@ 1.73 + int i_enum_query_1(struct sip_msg* _msg, char* _suffix, char* _str2); 1.74 + int i_enum_query_2(struct sip_msg* _msg, char* _suffix, char* _service); 1.75 + 1.76 ++/* 1.77 ++ * Make ISN query and if query succeeds, replace current uri with the 1.78 ++ * result of the query 1.79 ++ */ 1.80 ++int isn_query_0(struct sip_msg* _msg, char* _str1, char* _str2); 1.81 ++int isn_query_1(struct sip_msg* _msg, char* _suffix, char* _str2); 1.82 ++int isn_query_2(struct sip_msg* _msg, char* _suffix, char* _service); 1.83 ++ 1.84 + 1.85 + #endif /* ENUM_H */ 1.86 +Index: modules/enum/enum.c 1.87 +diff -Nau modules/enum/enum.c.orig modules/enum/enum.c 1.88 +--- modules/enum/enum.c.orig 2010-01-18 15:57:10.995902181 +0100 1.89 ++++ modules/enum/enum.c 2010-01-18 15:46:19.642209178 +0100 1.90 +@@ -736,6 +736,84 @@ 1.91 + } 1.92 + 1.93 + 1.94 ++/* 1.95 ++ * Call isn_query_2 with module parameter suffix and default service. 1.96 ++ */ 1.97 ++int isn_query_0(struct sip_msg* _msg, char* _str1, char* _str2) 1.98 ++{ 1.99 ++ return isn_query_2(_msg, (char *)(&isnsuffix), (char *)(&service)); 1.100 ++} 1.101 ++ 1.102 ++ 1.103 ++/* 1.104 ++ * Call isn_query_2 with given suffix and default service. 1.105 ++ */ 1.106 ++int isn_query_1(struct sip_msg* _msg, char* _suffix, char* _str2) 1.107 ++{ 1.108 ++ return isn_query_2(_msg, _suffix, (char *)(&service)); 1.109 ++} 1.110 ++ 1.111 ++ 1.112 ++/* 1.113 ++ * See documentation in README file. 1.114 ++ */ 1.115 ++int isn_query_2(struct sip_msg* _msg, char* _suffix, char* _service) 1.116 ++{ 1.117 ++ char *user_s = NULL; 1.118 ++ int user_len, i, j; 1.119 ++ char name[MAX_DOMAIN_SIZE] = {0}; 1.120 ++ char string[17] = {0}; 1.121 ++ char szItad[17] = {0}; 1.122 ++ size_t nItlen = 0; 1.123 ++ 1.124 ++ str *suffix, *service; 1.125 ++ 1.126 ++ suffix = (str*)_suffix; 1.127 ++ service = (str*)_service; 1.128 ++ 1.129 ++ if (parse_sip_msg_uri(_msg) < 0) { 1.130 ++ LM_ERR("Parsing of R-URI failed\n"); 1.131 ++ return -1; 1.132 ++ } 1.133 ++ 1.134 ++ user_s = _msg->parsed_uri.user.s; 1.135 ++ user_len = _msg->parsed_uri.user.len; 1.136 ++ 1.137 ++ memcpy(&(string[0]), user_s, user_len); 1.138 ++ string[user_len] = (char)0; 1.139 ++ 1.140 ++ /* Do primitive test for correct ISN format, */ 1.141 ++ /* and set szItad to the ISN ITAD (RFC 3872/2871). */ 1.142 ++ /* Correct ISN format guessed from freenum.org and IANA */ 1.143 ++ /* doc http://www.iana.org/assignments/trip-parameters/ */ 1.144 ++ { 1.145 ++ char *pAster = strchr(string, '*'); 1.146 ++ if (pAster && (nItlen = strspn(pAster + sizeof(char), "0123456789"))) 1.147 ++ strncpy(szItad, pAster + sizeof(char), nItlen); 1.148 ++ else { 1.149 ++ LM_ERR("R-URI user does not contain a valid ISN\n"); 1.150 ++ return -1; 1.151 ++ } 1.152 ++ } 1.153 ++ 1.154 ++ /* Ammend the original ENUM E.164 string logic to process */ 1.155 ++ /* ISN numbers instead, which include a nonreversed ITAD. */ 1.156 ++ i = user_len - nItlen - sizeof(char); /* Ex: *1212 */ 1.157 ++ j = 0; 1.158 ++ while (i--) { 1.159 ++ name[j] = user_s[i]; 1.160 ++ name[j + 1] = '.'; 1.161 ++ j = j + 2; 1.162 ++ } 1.163 ++ 1.164 ++ strcat(name + j, szItad); /* Copy the unreversed ITAD, */ 1.165 ++ name[j + nItlen] = '.'; /* and append a trailing dot. */ 1.166 ++ memcpy(name + j + nItlen + sizeof(char), suffix->s, suffix->len + 1); 1.167 ++ 1.168 ++ return do_query(_msg, string, name, service); 1.169 ++} 1.170 ++ 1.171 ++ 1.172 + /*********** INFRASTRUCTURE ENUM ***************/ 1.173 + 1.174 + /* 1.175 +Index: modules/enum/README 1.176 +diff -Nau modules/enum/README.orig modules/enum/README 1.177 +--- modules/enum/README.orig 2010-01-18 17:59:52.034172367 +0100 1.178 ++++ modules/enum/README 2010-01-18 18:01:30.730633377 +0100 1.179 +@@ -10,8 +10,8 @@ 1.180 + 1.181 + Copyright © 2002, 2003 Juha Heinanen 1.182 + Revision History 1.183 +- Revision $Revision: 5906 $ $Date: 2009-07-21 10:45:05 +0300 1.184 +- (Tue, 21 Jul 2009) $ 1.185 ++ Revision $Revision: 5907 $ $Date: 2010-01-18 10:45:05 +0100 1.186 ++ (Mon, 18 Jan 2010) $ 1.187 + __________________________________________________________ 1.188 + 1.189 + Table of Contents 1.190 +@@ -25,28 +25,32 @@ 1.191 + 1.3.1. domain_suffix (string) 1.192 + 1.3.2. tel_uri_params (string) 1.193 + 1.3.3. i_enum_suffix (string) 1.194 +- 1.3.4. branchlabel (string) 1.195 +- 1.3.5. bl_algorithm (string) 1.196 ++ 1.3.4. isn_suffix (string) 1.197 ++ 1.3.5. branchlabel (string) 1.198 ++ 1.3.6. bl_algorithm (string) 1.199 + 1.200 + 1.4. Exported Functions 1.201 + 1.202 + 1.4.1. enum_query(["suffix"[,"service"]]) 1.203 + 1.4.2. enum_pv_query("pvar"[,"suffix"[,"service"]]) 1.204 + 1.4.3. i_enum_query(["suffix"[,"service"]]) 1.205 +- 1.4.4. is_from_user_enum() 1.206 ++ 1.4.4. isn_query(["suffix"[,"service"]]) 1.207 ++ 1.4.5. is_from_user_enum() 1.208 + 1.209 + List of Examples 1.210 + 1.211 + 1.1. Setting domain_suffix module parameter 1.212 + 1.2. Setting tel_uri_params module parameter 1.213 + 1.3. Setting i_enum_suffix module parameter 1.214 +- 1.4. Setting brachlabel module parameter 1.215 +- 1.5. Zone file example 1.216 ++ 1.4. Setting isn_query usage module parameter 1.217 ++ 1.5. Setting branchlabel module parameter 1.218 + 1.6. Zone file example 1.219 +- 1.7. Setting the bl_algorithm module parameter 1.220 +- 1.8. enum_query usage 1.221 +- 1.9. enum_pv_query usage 1.222 +- 1.10. is_from_user_enum usage 1.223 ++ 1.7. Zone file example 1.224 ++ 1.8. Setting the bl_algorithm module parameter 1.225 ++ 1.9. enum_query usage 1.226 ++ 1.10. enum_pv_query usage 1.227 ++ 1.11. isn_query usage 1.228 ++ 1.12. is_from_user_enum usage 1.229 + 1.230 + Chapter 1. Admin Guide 1.231 + 1.232 +@@ -113,6 +117,22 @@ 1.233 + function does an enum lookup on the from user and returns true 1.234 + if found, false otherwise. 1.235 + 1.236 ++ In addition to standard ENUM, support for ISN (ITAD Subscriber 1.237 ++ Numbers) is provided as well. To allow ISN lookups to resolve, 1.238 ++ a different formatting algorithm is expected by the DNS server. 1.239 ++ Whereas a ENUM NAPTR record expects a DNS query of the form 1.240 ++ 9.8.7.6.5.4.3.2.1.<suffix>, ISN method expects a DNS query of 1.241 ++ the form 6.5.1212.<suffix>. That is, a valid ISN number includes 1.242 ++ a prefix of '56' in the example. The rest of the number is a 1.243 ++ ITAD (Internet Telephony Administrative Domain) as defined 1.244 ++ in RFCs 3872 and 2871, and as allocated by the IANA in 1.245 ++ http://www.iana.org/assignments/trip-parameters. The ITAD is 1.246 ++ left intact and not refersed as ENUM requires. To learn more 1.247 ++ about ISN please refer to documents at www.freenum.org. 1.248 ++ 1.249 ++ To complete a ISN lookup on the user part of the Request-URI, 1.250 ++ isn_query() is used instead of enum_query(). 1.251 ++ 1.252 + 1.2. Dependencies 1.253 + 1.254 + The module depends on the following modules (in the other words 1.255 +@@ -158,17 +178,27 @@ 1.256 + Example 1.3. Setting i_enum_suffix module parameter 1.257 + modparam("enum", "i_enum_suffix", "e1234.arpa.") 1.258 + 1.259 +-1.3.4. branchlabel (string) 1.260 ++1.3.4. isn_suffix (string) 1.261 ++ 1.262 ++ The domain suffix to be used for isn_query() lookups. Can be 1.263 ++ overridden by a parameter to isn_query. 1.264 ++ 1.265 ++ Default value is "freenum.org." 1.266 ++ 1.267 ++ Example 1.4. Setting isn_suffix module parameter 1.268 ++modparam("enum", "isn_suffix", "freenum.org.") 1.269 ++ 1.270 ++1.3.5. branchlabel (string) 1.271 + 1.272 + This parameter determines which label i_enum_query() will use 1.273 + to branch off to the infrastructure ENUM tree. 1.274 + 1.275 + Default value is ""i"" 1.276 + 1.277 +- Example 1.4. Setting brachlabel module parameter 1.278 ++ Example 1.5. Setting branchlabel module parameter 1.279 + modparam("enum", "branchlabel", "i") 1.280 + 1.281 +-1.3.5. bl_algorithm (string) 1.282 ++1.3.6. bl_algorithm (string) 1.283 + 1.284 + This parameter determines which algorithm i_enum_query() will 1.285 + use to select the position in the DNS tree where the 1.286 +@@ -182,7 +212,7 @@ 1.287 + [branchlabel].[reverse-country-code].[i_enum_suffix] to 1.288 + indicate after how many digits the label should in inserted. 1.289 + 1.290 +- Example 1.5. Zone file example 1.291 ++ Example 1.6. Zone file example 1.292 + i.1.e164.arpa. IN TXT "4" 1.293 + 9.9.9.8.7.6.5.i.4.3.2.1.e164.arpa. IN NAPTR "NAPTR content for +1 234 5 1.294 + 678 999" 1.295 +@@ -196,7 +226,7 @@ 1.296 + allocated yet. This version of the code uses 65300. See 1.297 + resolve.h. 1.298 + 1.299 +- Example 1.6. Zone file example 1.300 ++ Example 1.7. Zone file example 1.301 + i.1.e164.arpa. TYPE65300 \# 14 ( 1.302 + 04 ; position 1.303 + 01 69 ; separator 1.304 +@@ -208,7 +238,7 @@ 1.305 + 1.306 + Default value is "cc" 1.307 + 1.308 +- Example 1.7. Setting the bl_algorithm module parameter 1.309 ++ Example 1.8. Setting the bl_algorithm module parameter 1.310 + modparam("enum", "bl_algorithm", "txt") 1.311 + 1.312 + 1.4. Exported Functions 1.313 +@@ -225,7 +255,7 @@ 1.314 + 1.315 + This function can be used from REQUEST_ROUTE. 1.316 + 1.317 +- Example 1.8. enum_query usage 1.318 ++ Example 1.9. enum_query usage 1.319 + ... 1.320 + # search for "e2u+sip" in freenum.org 1.321 + enum_query("freenum.org."); 1.322 +@@ -262,7 +292,7 @@ 1.323 + 1.324 + This function can be used from REQUEST_ROUTE. 1.325 + 1.326 +- Example 1.9. enum_pv_query usage 1.327 ++ Example 1.10. enum_pv_query usage 1.328 + ... 1.329 + # search for "e2u+sip" in freenum.org 1.330 + enum_pv_query("$avp(i:100)", "freenum.org."); 1.331 +@@ -296,14 +326,42 @@ 1.332 + ftp://ftp.rfc-editor.org/in-notes/internet-drafts/draft-haberle 1.333 + r-carrier-enum-01.txt for the rationale behind this function. 1.334 + 1.335 +-1.4.4. is_from_user_enum() 1.336 ++1.4.4. isn_query(["suffix"[,"service"]]) 1.337 ++ 1.338 ++ The function performs a ISN query and rewrites the 1.339 ++ Request-URI with the result of the query. See Section 1.1, 1.340 ++ "Overview" for more information. 1.341 ++ 1.342 ++ Meaning of the parameters is as follows: 1.343 ++ * suffix - Suffix to be appended to the domain name. 1.344 ++ * service - Service string to be used in the service field. 1.345 ++ 1.346 ++ This function can be used from REQUEST_ROUTE. 1.347 ++ 1.348 ++ See ftp://www.ietf.org/rfc/rfc3872.txt and 1.349 ++ ftp://www.ietf.org/rfc/rfc2871.txt for information 1.350 ++ regarding the ITAD part of the ISN string. 1.351 ++ 1.352 ++ Example 1.11. isn_query usage 1.353 ++... 1.354 ++# search for "e2u+sip" in freenum.org 1.355 ++isn_query("freenum.org."); 1.356 ++... 1.357 ++# search for "e2u+sip" in default tree (configured as parameter) 1.358 ++enum_query(); 1.359 ++... 1.360 ++# search for "e2u+voice:sip" in freenum.org 1.361 ++enum_query("freenum.org.","voice"); 1.362 ++... 1.363 ++ 1.364 ++1.4.5. is_from_user_enum() 1.365 + 1.366 + Checks if the user part of from URI is found in an enum lookup. 1.367 + Returns 1 if yes and -1 if not. 1.368 + 1.369 + This function can be used from REQUEST_ROUTE. 1.370 + 1.371 +- Example 1.10. is_from_user_enum usage 1.372 ++ Example 1.12. is_from_user_enum usage 1.373 + ... 1.374 + if (is_from_user_enum()) { 1.375 + .... 1.376 +Index: modules/enum/doc/enum.xml 1.377 +diff -Nau modules/enum/doc/enum.xml.orig modules/enum/doc/enum.xml 1.378 +--- modules/enum/doc/enum.xml.orig 2009-10-16 02:31:52.000000000 +0200 1.379 ++++ modules/enum/doc/enum.xml 2010-01-18 18:01:15.954172402 +0100 1.380 +@@ -33,8 +33,8 @@ 1.381 + </copyright> 1.382 + <revhistory> 1.383 + <revision> 1.384 +- <revnumber>$Revision: 5901 $</revnumber> 1.385 +- <date>$Date: 2009-07-21 10:45:05 +0300 (Tue, 21 Jul 2009) $</date> 1.386 ++ <revnumber>$Revision: 5907 $</revnumber> 1.387 ++ <date>$Date: 2010-01-18 10:45:05 +0100 (Mon, 18 Jan 2010) $</date> 1.388 + </revision> 1.389 + </revhistory> 1.390 + </bookinfo> 1.391 +Index: modules/enum/doc/enum_admin.xml 1.392 +diff -Nau modules/enum/doc/enum_admin.xml.orig modules/enum/doc/enum_admin.xml 1.393 +--- modules/enum/doc/enum_admin.xml.orig 2010-01-18 12:33:30.053644000 +0100 1.394 ++++ modules/enum/doc/enum_admin.xml 2010-01-18 18:14:59.583157910 +0100 1.395 +@@ -75,6 +75,24 @@ 1.396 + and -1 if not. 1.397 + </para> 1.398 + <para> 1.399 ++ In addition to standard ENUM, support for ISN (ITAD Subscriber 1.400 ++ Numbers) is provided as well. To allow ISN lookups to resolve, 1.401 ++ a different formatting algorithm is expected by the DNS server. 1.402 ++ Whereas a ENUM NAPTR record expects a DNS query of the form 1.403 ++ 9.8.7.6.5.4.3.2.1.<suffix>, ISN method expects a DNS query of 1.404 ++ the form 6.5.1212.<suffix>. That is, a valid ISN number includes 1.405 ++ a prefix of '56' in the example. The rest of the number is a 1.406 ++ ITAD (Internet Telephony Administrative Domain) as defined 1.407 ++ in RFCs 3872 and 2871, and as allocated by the IANA in 1.408 ++ http://www.iana.org/assignments/trip-parameters. The ITAD is 1.409 ++ left intact and not refersed as ENUM requires. To learn more 1.410 ++ about ISN please refer to documents at www.freenum.org. 1.411 ++ </para> 1.412 ++ <para> 1.413 ++ To complete a ISN lookup on the user part of the Request-URI, 1.414 ++ isn_query() is used instead of enum_query(). 1.415 ++ </para> 1.416 ++ <para> 1.417 + Enum module also implements is_from_user_enum function. 1.418 + This function does an enum lookup on the from user and 1.419 + returns true if found, false otherwise. 1.420 +@@ -153,6 +171,22 @@ 1.421 + </example> 1.422 + </section> 1.423 + <section> 1.424 ++ <title><varname>isn_suffix</varname> (string)</title> 1.425 ++ <para> 1.426 ++ The domain suffix to be used for isn_query() lookups. Can 1.427 ++ be overridden by a parameter to isn_query. 1.428 ++ </para> 1.429 ++ <para> 1.430 ++ Default value is <quote>freenum.org.</quote> 1.431 ++ </para> 1.432 ++ <example> 1.433 ++ <title>Setting isn_suffix module parameter</title> 1.434 ++ <programlisting format="linespecific"> 1.435 ++modparam("enum", "isn_suffix", "freenum.org.") 1.436 ++</programlisting> 1.437 ++ </example> 1.438 ++ </section> 1.439 ++ <section> 1.440 + <title><varname>branchlabel</varname> (string)</title> 1.441 + <para> 1.442 + This parameter determines which label i_enum_query() will use 1.443 +@@ -162,7 +196,7 @@ 1.444 + Default value is <quote>"i"</quote> 1.445 + </para> 1.446 + <example> 1.447 +- <title>Setting brachlabel module parameter</title> 1.448 ++ <title>Setting branchlabel module parameter</title> 1.449 + <programlisting format="linespecific"> 1.450 + modparam("enum", "branchlabel", "i") 1.451 + </programlisting> 1.452 +@@ -353,6 +387,53 @@ 1.453 + </section> 1.454 + 1.455 + <section> 1.456 ++ <title> 1.457 ++ <function moreinfo="none">isn_query(["suffix"[,"service"]])</function> 1.458 ++ </title> 1.459 ++ <para> 1.460 ++ The function performs a ISN query and rewrites the Request-URI with 1.461 ++ the result of the query. See <xref linkend="sec-overview"/> for more 1.462 ++ information. 1.463 ++ </para> 1.464 ++ <para>Meaning of the parameters is as follows:</para> 1.465 ++ <itemizedlist> 1.466 ++ <listitem> 1.467 ++ <para><emphasis>suffix</emphasis> - Suffix to be appended to the 1.468 ++ domain name. 1.469 ++ </para> 1.470 ++ </listitem> 1.471 ++ <listitem> 1.472 ++ <para><emphasis>service</emphasis> - Service string to be used in 1.473 ++ the service field. 1.474 ++ </para> 1.475 ++ </listitem> 1.476 ++ </itemizedlist> 1.477 ++ <para> 1.478 ++ This function can be used from REQUEST_ROUTE. 1.479 ++ </para> 1.480 ++ <para> 1.481 ++ See ftp://www.ietf.org/rfc/rfc3872.txt and 1.482 ++ ftp://www.ietf.org/rfc/rfc2871.txt for information 1.483 ++ regarding the ITAD part of the ISN string. 1.484 ++ </para> 1.485 ++ <example> 1.486 ++ <title><function moreinfo="none">isn_query</function> usage</title> 1.487 ++ <programlisting format="linespecific"> 1.488 ++... 1.489 ++# search for "e2u+sip" in freenum.org 1.490 ++isn_query("freenum.org."); 1.491 ++... 1.492 ++# search for "e2u+sip" in default tree (configured as parameter) 1.493 ++isn_query(); 1.494 ++... 1.495 ++# search for "e2u+voice:sip" in freenum.org 1.496 ++isn_query("freenum.org.","voice"); 1.497 ++... 1.498 ++</programlisting> 1.499 ++ </example> 1.500 ++ </section> 1.501 ++ 1.502 ++ <section> 1.503 + <title><function moreinfo="none">is_from_user_enum()</function></title> 1.504 + <para> 1.505 + Checks if the user part of from <abbrev>URI</abbrev>
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/opensips/enum-isn.txt Mon Jan 18 19:59:51 2010 +0100 2.3 @@ -0,0 +1,47 @@ 2.4 +ISN (ITAD Subscriber Number) lookup integration contribution code 2.5 + 2.6 +Contribution 2.7 + 2.8 +This contribution introduces ISN formatting logic into the OpenSIPS 2.9 +ENUM module, allowing it to perform NAPTR based ISN lookups on the 2.10 +user part of the Request-URI in addition to the existing ENUM lookups. 2.11 + 2.12 +Rationale 2.13 + 2.14 +This extends the utility of the existing E.164 formatting logic which 2.15 +previously caused valid ISN lookups to fail (although the OpenSIPS 2.16 +documentation did suggest that lookups to freenum.org would succeed.) 2.17 + 2.18 +Compliance 2.19 + 2.20 +The author believes that the introduced logic complies with the 2.21 +relevant ITAD standards as defined by RFC 3872 and RFC 2871, however 2.22 +it seems that at this time ISN is rather loosely defined according to 2.23 +nonstandard documentation provided by freenum.org. 2.24 + 2.25 +Location 2.26 + 2.27 +http://scm.europalab.com/contrib/opensips/ 2.28 +http://scm.europalab.com/contrib/file/tip/opensips/ 2.29 + 2.30 +Instructions 2.31 + 2.32 +To integrate this contributed logic into the source code tree of 2.33 +a OpenSIPS distribution, download the unified diff and use the 2.34 +patch(1) command: 2.35 + 2.36 + $ cd /tmp && mkdir enum-patch && cd enum-patch 2.37 + $ wget http://scm.europalab.com/contrib/raw-file/tip/opensips/enum-isn.diff 2.38 + $ tar zxf /tmp/opensips-<version>-tls.tar.gz 2.39 + $ cd opensips-<version>-tls 2.40 + $ patch -p0 <../enum-isn.diff 2.41 + 2.42 +Disclaimer 2.43 + 2.44 +This software contribution is based on source code from OpenSIPS SVN 2.45 +revision 6511. The author makes no guarantees as to this contribution. 2.46 +A user who downloads and executes it does so at his own risk. 2.47 + 2.48 +Michael Schloh von Bennewitz 2.49 +http://michael.schloh.com/ 2.50 +Monday, 18. January 2010
3.1 --- a/opensips/modules/enum/README Mon Jan 18 19:47:23 2010 +0100 3.2 +++ b/opensips/modules/enum/README Mon Jan 18 19:59:51 2010 +0100 3.3 @@ -10,8 +10,8 @@ 3.4 3.5 Copyright © 2002, 2003 Juha Heinanen 3.6 Revision History 3.7 - Revision $Revision: 5906 $ $Date: 2009-07-21 10:45:05 +0300 3.8 - (Tue, 21 Jul 2009) $ 3.9 + Revision $Revision: 5907 $ $Date: 2010-01-18 10:45:05 +0100 3.10 + (Mon, 18 Jan 2010) $ 3.11 __________________________________________________________ 3.12 3.13 Table of Contents 3.14 @@ -25,28 +25,32 @@ 3.15 1.3.1. domain_suffix (string) 3.16 1.3.2. tel_uri_params (string) 3.17 1.3.3. i_enum_suffix (string) 3.18 - 1.3.4. branchlabel (string) 3.19 - 1.3.5. bl_algorithm (string) 3.20 + 1.3.4. isn_suffix (string) 3.21 + 1.3.5. branchlabel (string) 3.22 + 1.3.6. bl_algorithm (string) 3.23 3.24 1.4. Exported Functions 3.25 3.26 1.4.1. enum_query(["suffix"[,"service"]]) 3.27 1.4.2. enum_pv_query("pvar"[,"suffix"[,"service"]]) 3.28 1.4.3. i_enum_query(["suffix"[,"service"]]) 3.29 - 1.4.4. is_from_user_enum() 3.30 + 1.4.4. isn_query(["suffix"[,"service"]]) 3.31 + 1.4.5. is_from_user_enum() 3.32 3.33 List of Examples 3.34 3.35 1.1. Setting domain_suffix module parameter 3.36 1.2. Setting tel_uri_params module parameter 3.37 1.3. Setting i_enum_suffix module parameter 3.38 - 1.4. Setting brachlabel module parameter 3.39 - 1.5. Zone file example 3.40 + 1.4. Setting isn_query usage module parameter 3.41 + 1.5. Setting branchlabel module parameter 3.42 1.6. Zone file example 3.43 - 1.7. Setting the bl_algorithm module parameter 3.44 - 1.8. enum_query usage 3.45 - 1.9. enum_pv_query usage 3.46 - 1.10. is_from_user_enum usage 3.47 + 1.7. Zone file example 3.48 + 1.8. Setting the bl_algorithm module parameter 3.49 + 1.9. enum_query usage 3.50 + 1.10. enum_pv_query usage 3.51 + 1.11. isn_query usage 3.52 + 1.12. is_from_user_enum usage 3.53 3.54 Chapter 1. Admin Guide 3.55 3.56 @@ -113,6 +117,22 @@ 3.57 function does an enum lookup on the from user and returns true 3.58 if found, false otherwise. 3.59 3.60 + In addition to standard ENUM, support for ISN (ITAD Subscriber 3.61 + Numbers) is provided as well. To allow ISN lookups to resolve, 3.62 + a different formatting algorithm is expected by the DNS server. 3.63 + Whereas a ENUM NAPTR record expects a DNS query of the form 3.64 + 9.8.7.6.5.4.3.2.1.<suffix>, ISN method expects a DNS query of 3.65 + the form 6.5.1212.<suffix>. That is, a valid ISN number includes 3.66 + a prefix of '56' in the example. The rest of the number is a 3.67 + ITAD (Internet Telephony Administrative Domain) as defined 3.68 + in RFCs 3872 and 2871, and as allocated by the IANA in 3.69 + http://www.iana.org/assignments/trip-parameters. The ITAD is 3.70 + left intact and not refersed as ENUM requires. To learn more 3.71 + about ISN please refer to documents at www.freenum.org. 3.72 + 3.73 + To complete a ISN lookup on the user part of the Request-URI, 3.74 + isn_query() is used instead of enum_query(). 3.75 + 3.76 1.2. Dependencies 3.77 3.78 The module depends on the following modules (in the other words 3.79 @@ -158,17 +178,27 @@ 3.80 Example 1.3. Setting i_enum_suffix module parameter 3.81 modparam("enum", "i_enum_suffix", "e1234.arpa.") 3.82 3.83 -1.3.4. branchlabel (string) 3.84 +1.3.4. isn_suffix (string) 3.85 + 3.86 + The domain suffix to be used for isn_query() lookups. Can be 3.87 + overridden by a parameter to isn_query. 3.88 + 3.89 + Default value is "freenum.org." 3.90 + 3.91 + Example 1.4. Setting isn_suffix module parameter 3.92 +modparam("enum", "isn_suffix", "freenum.org.") 3.93 + 3.94 +1.3.5. branchlabel (string) 3.95 3.96 This parameter determines which label i_enum_query() will use 3.97 to branch off to the infrastructure ENUM tree. 3.98 3.99 Default value is ""i"" 3.100 3.101 - Example 1.4. Setting brachlabel module parameter 3.102 + Example 1.5. Setting branchlabel module parameter 3.103 modparam("enum", "branchlabel", "i") 3.104 3.105 -1.3.5. bl_algorithm (string) 3.106 +1.3.6. bl_algorithm (string) 3.107 3.108 This parameter determines which algorithm i_enum_query() will 3.109 use to select the position in the DNS tree where the 3.110 @@ -182,7 +212,7 @@ 3.111 [branchlabel].[reverse-country-code].[i_enum_suffix] to 3.112 indicate after how many digits the label should in inserted. 3.113 3.114 - Example 1.5. Zone file example 3.115 + Example 1.6. Zone file example 3.116 i.1.e164.arpa. IN TXT "4" 3.117 9.9.9.8.7.6.5.i.4.3.2.1.e164.arpa. IN NAPTR "NAPTR content for +1 234 5 3.118 678 999" 3.119 @@ -196,7 +226,7 @@ 3.120 allocated yet. This version of the code uses 65300. See 3.121 resolve.h. 3.122 3.123 - Example 1.6. Zone file example 3.124 + Example 1.7. Zone file example 3.125 i.1.e164.arpa. TYPE65300 \# 14 ( 3.126 04 ; position 3.127 01 69 ; separator 3.128 @@ -208,7 +238,7 @@ 3.129 3.130 Default value is "cc" 3.131 3.132 - Example 1.7. Setting the bl_algorithm module parameter 3.133 + Example 1.8. Setting the bl_algorithm module parameter 3.134 modparam("enum", "bl_algorithm", "txt") 3.135 3.136 1.4. Exported Functions 3.137 @@ -225,7 +255,7 @@ 3.138 3.139 This function can be used from REQUEST_ROUTE. 3.140 3.141 - Example 1.8. enum_query usage 3.142 + Example 1.9. enum_query usage 3.143 ... 3.144 # search for "e2u+sip" in freenum.org 3.145 enum_query("freenum.org."); 3.146 @@ -262,7 +292,7 @@ 3.147 3.148 This function can be used from REQUEST_ROUTE. 3.149 3.150 - Example 1.9. enum_pv_query usage 3.151 + Example 1.10. enum_pv_query usage 3.152 ... 3.153 # search for "e2u+sip" in freenum.org 3.154 enum_pv_query("$avp(i:100)", "freenum.org."); 3.155 @@ -296,14 +326,42 @@ 3.156 ftp://ftp.rfc-editor.org/in-notes/internet-drafts/draft-haberle 3.157 r-carrier-enum-01.txt for the rationale behind this function. 3.158 3.159 -1.4.4. is_from_user_enum() 3.160 +1.4.4. isn_query(["suffix"[,"service"]]) 3.161 + 3.162 + The function performs a ISN query and rewrites the 3.163 + Request-URI with the result of the query. See Section 1.1, 3.164 + "Overview" for more information. 3.165 + 3.166 + Meaning of the parameters is as follows: 3.167 + * suffix - Suffix to be appended to the domain name. 3.168 + * service - Service string to be used in the service field. 3.169 + 3.170 + This function can be used from REQUEST_ROUTE. 3.171 + 3.172 + See ftp://www.ietf.org/rfc/rfc3872.txt and 3.173 + ftp://www.ietf.org/rfc/rfc2871.txt for information 3.174 + regarding the ITAD part of the ISN string. 3.175 + 3.176 + Example 1.11. isn_query usage 3.177 +... 3.178 +# search for "e2u+sip" in freenum.org 3.179 +isn_query("freenum.org."); 3.180 +... 3.181 +# search for "e2u+sip" in default tree (configured as parameter) 3.182 +enum_query(); 3.183 +... 3.184 +# search for "e2u+voice:sip" in freenum.org 3.185 +enum_query("freenum.org.","voice"); 3.186 +... 3.187 + 3.188 +1.4.5. is_from_user_enum() 3.189 3.190 Checks if the user part of from URI is found in an enum lookup. 3.191 Returns 1 if yes and -1 if not. 3.192 3.193 This function can be used from REQUEST_ROUTE. 3.194 3.195 - Example 1.10. is_from_user_enum usage 3.196 + Example 1.12. is_from_user_enum usage 3.197 ... 3.198 if (is_from_user_enum()) { 3.199 ....
4.1 --- a/opensips/modules/enum/doc/enum.xml Mon Jan 18 19:47:23 2010 +0100 4.2 +++ b/opensips/modules/enum/doc/enum.xml Mon Jan 18 19:59:51 2010 +0100 4.3 @@ -33,8 +33,8 @@ 4.4 </copyright> 4.5 <revhistory> 4.6 <revision> 4.7 - <revnumber>$Revision: 5901 $</revnumber> 4.8 - <date>$Date: 2009-07-21 10:45:05 +0300 (Tue, 21 Jul 2009) $</date> 4.9 + <revnumber>$Revision: 5907 $</revnumber> 4.10 + <date>$Date: 2010-01-18 10:45:05 +0100 (Mon, 18 Jan 2010) $</date> 4.11 </revision> 4.12 </revhistory> 4.13 </bookinfo>
5.1 --- a/opensips/modules/enum/doc/enum_admin.xml Mon Jan 18 19:47:23 2010 +0100 5.2 +++ b/opensips/modules/enum/doc/enum_admin.xml Mon Jan 18 19:59:51 2010 +0100 5.3 @@ -75,6 +75,24 @@ 5.4 and -1 if not. 5.5 </para> 5.6 <para> 5.7 + In addition to standard ENUM, support for ISN (ITAD Subscriber 5.8 + Numbers) is provided as well. To allow ISN lookups to resolve, 5.9 + a different formatting algorithm is expected by the DNS server. 5.10 + Whereas a ENUM NAPTR record expects a DNS query of the form 5.11 + 9.8.7.6.5.4.3.2.1.<suffix>, ISN method expects a DNS query of 5.12 + the form 6.5.1212.<suffix>. That is, a valid ISN number includes 5.13 + a prefix of '56' in the example. The rest of the number is a 5.14 + ITAD (Internet Telephony Administrative Domain) as defined 5.15 + in RFCs 3872 and 2871, and as allocated by the IANA in 5.16 + http://www.iana.org/assignments/trip-parameters. The ITAD is 5.17 + left intact and not refersed as ENUM requires. To learn more 5.18 + about ISN please refer to documents at www.freenum.org. 5.19 + </para> 5.20 + <para> 5.21 + To complete a ISN lookup on the user part of the Request-URI, 5.22 + isn_query() is used instead of enum_query(). 5.23 + </para> 5.24 + <para> 5.25 Enum module also implements is_from_user_enum function. 5.26 This function does an enum lookup on the from user and 5.27 returns true if found, false otherwise. 5.28 @@ -153,6 +171,22 @@ 5.29 </example> 5.30 </section> 5.31 <section> 5.32 + <title><varname>isn_suffix</varname> (string)</title> 5.33 + <para> 5.34 + The domain suffix to be used for isn_query() lookups. Can 5.35 + be overridden by a parameter to isn_query. 5.36 + </para> 5.37 + <para> 5.38 + Default value is <quote>freenum.org.</quote> 5.39 + </para> 5.40 + <example> 5.41 + <title>Setting isn_suffix module parameter</title> 5.42 + <programlisting format="linespecific"> 5.43 +modparam("enum", "isn_suffix", "freenum.org.") 5.44 +</programlisting> 5.45 + </example> 5.46 + </section> 5.47 + <section> 5.48 <title><varname>branchlabel</varname> (string)</title> 5.49 <para> 5.50 This parameter determines which label i_enum_query() will use 5.51 @@ -162,7 +196,7 @@ 5.52 Default value is <quote>"i"</quote> 5.53 </para> 5.54 <example> 5.55 - <title>Setting brachlabel module parameter</title> 5.56 + <title>Setting branchlabel module parameter</title> 5.57 <programlisting format="linespecific"> 5.58 modparam("enum", "branchlabel", "i") 5.59 </programlisting> 5.60 @@ -353,6 +387,53 @@ 5.61 </section> 5.62 5.63 <section> 5.64 + <title> 5.65 + <function moreinfo="none">isn_query(["suffix"[,"service"]])</function> 5.66 + </title> 5.67 + <para> 5.68 + The function performs a ISN query and rewrites the Request-URI with 5.69 + the result of the query. See <xref linkend="sec-overview"/> for more 5.70 + information. 5.71 + </para> 5.72 + <para>Meaning of the parameters is as follows:</para> 5.73 + <itemizedlist> 5.74 + <listitem> 5.75 + <para><emphasis>suffix</emphasis> - Suffix to be appended to the 5.76 + domain name. 5.77 + </para> 5.78 + </listitem> 5.79 + <listitem> 5.80 + <para><emphasis>service</emphasis> - Service string to be used in 5.81 + the service field. 5.82 + </para> 5.83 + </listitem> 5.84 + </itemizedlist> 5.85 + <para> 5.86 + This function can be used from REQUEST_ROUTE. 5.87 + </para> 5.88 + <para> 5.89 + See ftp://www.ietf.org/rfc/rfc3872.txt and 5.90 + ftp://www.ietf.org/rfc/rfc2871.txt for information 5.91 + regarding the ITAD part of the ISN string. 5.92 + </para> 5.93 + <example> 5.94 + <title><function moreinfo="none">isn_query</function> usage</title> 5.95 + <programlisting format="linespecific"> 5.96 +... 5.97 +# search for "e2u+sip" in freenum.org 5.98 +isn_query("freenum.org."); 5.99 +... 5.100 +# search for "e2u+sip" in default tree (configured as parameter) 5.101 +isn_query(); 5.102 +... 5.103 +# search for "e2u+voice:sip" in freenum.org 5.104 +isn_query("freenum.org.","voice"); 5.105 +... 5.106 +</programlisting> 5.107 + </example> 5.108 + </section> 5.109 + 5.110 + <section> 5.111 <title><function moreinfo="none">is_from_user_enum()</function></title> 5.112 <para> 5.113 Checks if the user part of from <abbrev>URI</abbrev>
6.1 --- a/opensips/modules/enum/enum.c Mon Jan 18 19:47:23 2010 +0100 6.2 +++ b/opensips/modules/enum/enum.c Mon Jan 18 19:59:51 2010 +0100 6.3 @@ -736,6 +736,84 @@ 6.4 } 6.5 6.6 6.7 +/* 6.8 + * Call isn_query_2 with module parameter suffix and default service. 6.9 + */ 6.10 +int isn_query_0(struct sip_msg* _msg, char* _str1, char* _str2) 6.11 +{ 6.12 + return isn_query_2(_msg, (char *)(&isnsuffix), (char *)(&service)); 6.13 +} 6.14 + 6.15 + 6.16 +/* 6.17 + * Call isn_query_2 with given suffix and default service. 6.18 + */ 6.19 +int isn_query_1(struct sip_msg* _msg, char* _suffix, char* _str2) 6.20 +{ 6.21 + return isn_query_2(_msg, _suffix, (char *)(&service)); 6.22 +} 6.23 + 6.24 + 6.25 +/* 6.26 + * See documentation in README file. 6.27 + */ 6.28 +int isn_query_2(struct sip_msg* _msg, char* _suffix, char* _service) 6.29 +{ 6.30 + char *user_s = NULL; 6.31 + int user_len, i, j; 6.32 + char name[MAX_DOMAIN_SIZE] = {0}; 6.33 + char string[17] = {0}; 6.34 + char szItad[17] = {0}; 6.35 + size_t nItlen = 0; 6.36 + 6.37 + str *suffix, *service; 6.38 + 6.39 + suffix = (str*)_suffix; 6.40 + service = (str*)_service; 6.41 + 6.42 + if (parse_sip_msg_uri(_msg) < 0) { 6.43 + LM_ERR("Parsing of R-URI failed\n"); 6.44 + return -1; 6.45 + } 6.46 + 6.47 + user_s = _msg->parsed_uri.user.s; 6.48 + user_len = _msg->parsed_uri.user.len; 6.49 + 6.50 + memcpy(&(string[0]), user_s, user_len); 6.51 + string[user_len] = (char)0; 6.52 + 6.53 + /* Do primitive test for correct ISN format, */ 6.54 + /* and set szItad to the ISN ITAD (RFC 3872/2871). */ 6.55 + /* Correct ISN format guessed from freenum.org and IANA */ 6.56 + /* doc http://www.iana.org/assignments/trip-parameters/ */ 6.57 + { 6.58 + char *pAster = strchr(string, '*'); 6.59 + if (pAster && (nItlen = strspn(pAster + sizeof(char), "0123456789"))) 6.60 + strncpy(szItad, pAster + sizeof(char), nItlen); 6.61 + else { 6.62 + LM_ERR("R-URI user does not contain a valid ISN\n"); 6.63 + return -1; 6.64 + } 6.65 + } 6.66 + 6.67 + /* Ammend the original ENUM E.164 string logic to process */ 6.68 + /* ISN numbers instead, which include a nonreversed ITAD. */ 6.69 + i = user_len - nItlen - sizeof(char); /* Ex: *1212 */ 6.70 + j = 0; 6.71 + while (i--) { 6.72 + name[j] = user_s[i]; 6.73 + name[j + 1] = '.'; 6.74 + j = j + 2; 6.75 + } 6.76 + 6.77 + strcat(name + j, szItad); /* Copy the unreversed ITAD, */ 6.78 + name[j + nItlen] = '.'; /* and append a trailing dot. */ 6.79 + memcpy(name + j + nItlen + sizeof(char), suffix->s, suffix->len + 1); 6.80 + 6.81 + return do_query(_msg, string, name, service); 6.82 +} 6.83 + 6.84 + 6.85 /*********** INFRASTRUCTURE ENUM ***************/ 6.86 6.87 /*
7.1 --- a/opensips/modules/enum/enum.h Mon Jan 18 19:47:23 2010 +0100 7.2 +++ b/opensips/modules/enum/enum.h Mon Jan 18 19:59:51 2010 +0100 7.3 @@ -66,5 +66,13 @@ 7.4 int i_enum_query_1(struct sip_msg* _msg, char* _suffix, char* _str2); 7.5 int i_enum_query_2(struct sip_msg* _msg, char* _suffix, char* _service); 7.6 7.7 +/* 7.8 + * Make ISN query and if query succeeds, replace current uri with the 7.9 + * result of the query 7.10 + */ 7.11 +int isn_query_0(struct sip_msg* _msg, char* _str1, char* _str2); 7.12 +int isn_query_1(struct sip_msg* _msg, char* _suffix, char* _str2); 7.13 +int isn_query_2(struct sip_msg* _msg, char* _suffix, char* _service); 7.14 + 7.15 7.16 #endif /* ENUM_H */
8.1 --- a/opensips/modules/enum/enum_mod.c Mon Jan 18 19:47:23 2010 +0100 8.2 +++ b/opensips/modules/enum/enum_mod.c Mon Jan 18 19:59:51 2010 +0100 8.3 @@ -55,6 +55,8 @@ 8.4 char* i_enum_suffix = "e164.arpa."; 8.5 char* bl_algorithm = "cc"; 8.6 8.7 +char* isn_suffix = "freenum.org."; 8.8 + 8.9 8.10 /* 8.11 * Internal module variables 8.12 @@ -67,6 +69,8 @@ 8.13 str i_branchlabel; 8.14 str i_bl_alg; 8.15 8.16 +str isnsuffix; 8.17 + 8.18 8.19 /* 8.20 * Exported functions 8.21 @@ -94,6 +98,11 @@ 8.22 REQUEST_ROUTE}, 8.23 {"i_enum_query", (cmd_function)i_enum_query_2, 2, fixup_str_str, 0, 8.24 REQUEST_ROUTE}, 8.25 + {"isn_query", (cmd_function)isn_query_0, 0, 0, 0, REQUEST_ROUTE}, 8.26 + {"isn_query", (cmd_function)isn_query_1, 1, fixup_str_null, 8.27 + fixup_free_str_null, REQUEST_ROUTE}, 8.28 + {"isn_query", (cmd_function)isn_query_2, 2, fixup_str_str, 8.29 + fixup_free_str_str, REQUEST_ROUTE}, 8.30 {0, 0, 0, 0, 0, 0} 8.31 }; 8.32 8.33 @@ -107,6 +116,7 @@ 8.34 {"branchlabel", STR_PARAM, &branchlabel}, 8.35 {"i_enum_suffix", STR_PARAM, &i_enum_suffix}, 8.36 {"bl_algorithm", STR_PARAM, &bl_algorithm}, 8.37 + {"isn_suffix", STR_PARAM, &isn_suffix}, 8.38 {0, 0, 0} 8.39 }; 8.40 8.41 @@ -152,6 +162,9 @@ 8.42 i_bl_alg.s = bl_algorithm; 8.43 i_bl_alg.len = strlen(bl_algorithm); 8.44 8.45 + isnsuffix.s = isn_suffix; 8.46 + isnsuffix.len = strlen(isnsuffix.s); 8.47 + 8.48 return 0; 8.49 } 8.50
9.1 --- a/opensips/modules/enum/enum_mod.h Mon Jan 18 19:47:23 2010 +0100 9.2 +++ b/opensips/modules/enum/enum_mod.h Mon Jan 18 19:59:51 2010 +0100 9.3 @@ -41,5 +41,7 @@ 9.4 extern str i_branchlabel; /* the label branching off the infrastructure tree */ 9.5 extern str i_bl_alg; /* how to know where to branch off */ 9.6 9.7 +extern str isnsuffix; /* str version of isn_suffix */ 9.8 + 9.9 9.10 #endif /* ENUM_MOD_H */