domainpolicy.c

Go to the documentation of this file.
00001 /* 
00002  * $Id$
00003  *
00004  * Copyright (C) 2006 Otmar Lendl & Klaus Darilion
00005  *
00006  * Based on the ENUM and domain module.
00007  *
00008  * This file is part of Kamailio, a free SIP server.
00009  *
00010  * Kamailio is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version
00014  *
00015  * Kamailio is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License 
00021  * along with this program; if not, write to the Free Software 
00022  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00023  *
00024  * History:
00025  * --------
00026  *  2006-04-20  Initial Version
00027  *  2006-09-08  Updated to -02 version, added support for D2P+SIP:std
00028  */
00029 
00030 
00037 #include "domainpolicy_mod.h"
00038 #include "domainpolicy.h"
00039 #include "../../lib/srdb1/db.h"
00040 #include "../../parser/parse_uri.h"
00041 #include "../../parser/parse_from.h"
00042 #include "../../ut.h"
00043 #include "../../dset.h"
00044 #include "../../route.h"
00045 #include "../../ip_addr.h"
00046 #include "../../socket_info.h"
00047 
00048 #include "../../resolve.h"
00049 #include "../../lib/kcore/regexp.h"
00050 
00051 #define IS_D2PNAPTR(naptr) ((naptr->services_len >= 7) && (!strncasecmp("D2P+SIP", naptr->services, 7)))
00052 
00053 static db1_con_t* db_handle=0;
00054 static db_func_t domainpolicy_dbf;
00055 
00056 /*
00057  * some helper structs + functions to help build up the AVPs.
00058  * We can't immediately store them in AVPs as a later non-matched
00059  * rule can result in junking all the AVPs added up to that moment.
00060  *
00061  * Thus we store them temporarily in an avp_stack.
00062  */
00063 #define AVPMAXSIZE 120
00064 #define AVPSTACKSIZE 32
00065 
00066 struct avp {
00067     char att[AVPMAXSIZE];
00068     char val[AVPMAXSIZE];
00069 };
00070 
00071 struct avp_stack {
00072     int succeeded;
00073     int i;
00074     struct avp avp[AVPSTACKSIZE];
00075 };
00076 
00077 /*
00078  * Push avp-pair on stack.
00079  *
00080  * return 0 on failure.
00081  */
00082 static int stack_push(struct avp_stack *stack, char *att, char *val) {
00083     int i;
00084     if (stack->i >= (AVPSTACKSIZE-1)) {
00085         LM_ERR("exceeded stack size.!\n");
00086         return(0);
00087     }
00088 
00089     i = (stack->i)++;
00090     strncpy(stack->avp[i].att, att, AVPMAXSIZE - 1);
00091     strncpy(stack->avp[i].val, val, AVPMAXSIZE - 1);
00092 
00093     stack->succeeded = 1;
00094 
00095     return(1);
00096 }
00097 
00098 
00099 static void stack_reset(struct avp_stack *stack) {
00100     stack->i            = 0;
00101     stack->succeeded    = 0;
00102 }
00103 
00104 static int stack_succeeded(struct avp_stack *stack) {
00105     return(stack->succeeded);
00106 }
00107 
00108 static void stack_to_avp(struct avp_stack *stack) {
00109         int j;
00110         int_str  avp_att;
00111         int_str  avp_val;
00112         unsigned int intval;
00113 
00114         intval=2;
00115 
00116         for(j=0; j< stack->i; j++) {
00117                 /* AVP names can be integer or string based */
00118                 LM_DBG("process AVP: name='%s' value='%s'\n", 
00119                                         stack->avp[j].att, stack->avp[j].val);
00120 
00121                 /* if the second character is a ':', ignore the prefix
00122                  * this allows specifying the name with i:... or s:... too
00123                  * Note: the first character is ignored!!!
00124                  */
00125                 if ( stack->avp[j].att[0] && stack->avp[j].att[1]==':' ) { 
00126 
00127                         switch (stack->avp[j].att[0]) {
00128                         case 'i':
00129                         case 'I':
00130                                 intval = 1;
00131                                 break;
00132                         case 's':
00133                         case 'S':
00134                                 intval = 0;
00135                                 break;
00136                         default:
00137                                 LM_ERR("invalid type '%c'\n",stack->avp[j].att[0]);
00138                                 continue;
00139                         }
00140                         avp_att.s.s = (char *) &(stack->avp[j].att[2]); 
00141                 } else {
00142                         avp_att.s.s = stack->avp[j].att;
00143                 }
00144                 avp_att.s.len = strlen(avp_att.s.s);
00145                 if (!avp_att.s.len) {
00146                         LM_ERR("empty AVP name string!\n");
00147                         continue;
00148                 }
00149 
00150                 avp_val.s.s = stack->avp[j].val; 
00151                 avp_val.s.len = strlen(avp_val.s.s);
00152 
00153                 if (intval==1) {
00154                         /* integer type explicitely forced with i: */
00155                         if (str2int(&(avp_att.s), &intval) == 0) {
00156                                 /* integer named AVP */
00157                                 if (!intval) {
00158                                         LM_ERR("nameless integer AVP!\n");
00159                                         continue;
00160                                 }
00161                                 avp_att.n = intval;
00162                                 LM_DBG("create integer named AVP <i:%d>\n", avp_att.n);
00163                                 add_avp(AVP_VAL_STR, avp_att, avp_val);
00164                                 continue;
00165                         } else { 
00166                                 LM_ERR("integer AVP is not an integer!\n");
00167                                 continue;
00168                         }
00169                 } 
00170 
00171                 if (intval==2) {
00172                         /* string type undefined */
00173                         /* convert name into integer. if it succeeds then it is
00174                          * an integer named AVP. If it fails, then it is a string
00175                          * named AVP
00176                          */
00177                         if (str2int(&(avp_att.s), &intval) == 0) {
00178                                 /* integer named AVP */
00179                                 if (!intval) {
00180                                         LM_ERR("nameless integer AVP!\n");
00181                                         continue;
00182                                 }
00183                                 avp_att.n = intval;
00184                                 LM_DBG("create integer named AVP <i:%d>\n", avp_att.n);
00185                                 add_avp(AVP_VAL_STR, avp_att, avp_val);
00186                                 continue;
00187                         } else { 
00188                                 LM_DBG("create string named AVP <s:%.*s>\n", 
00189                                                 avp_att.s.len, ZSW(avp_att.s.s));
00190                                 add_avp(AVP_NAME_STR | AVP_VAL_STR, avp_att, avp_val);
00191                                 continue;
00192                         }
00193                 } 
00194 
00195                 /* intval==0, string type explicitely forced with s: */
00196                 LM_DBG("create string named AVP <s:%.*s>\n", 
00197                                 avp_att.s.len, ZSW(avp_att.s.s));
00198                 add_avp(AVP_NAME_STR | AVP_VAL_STR, avp_att, avp_val);
00199         }
00200 }
00201 
00202 /* helper db functions*/
00203 
00209 int domainpolicy_db_bind(const str* db_url)
00210 {
00211         if (db_bind_mod(db_url, &domainpolicy_dbf )) {
00212                 LM_CRIT("cannot bind to database module! "
00213                 "Did you forget to load a database module ?\n");
00214                 return -1;
00215         }
00216         return 0;
00217 }
00218 
00219 
00225 int domainpolicy_db_init(const str* db_url)
00226 {
00227         if (domainpolicy_dbf.init==0){
00228                 LM_CRIT("unbound database module\n");
00229                 goto error;
00230         }
00231         db_handle=domainpolicy_dbf.init(db_url);
00232         if (db_handle==0){
00233                 LM_CRIT("cannot initialize database connection\n");
00234                 goto error;
00235         }
00236         return 0;
00237 error:
00238         return -1;
00239 }
00240 
00241 
00245 void domainpolicy_db_close(void)
00246 {
00247         if (db_handle && domainpolicy_dbf.close){
00248                 domainpolicy_dbf.close(db_handle);
00249                 db_handle=0;
00250         }
00251 }
00252 
00253 
00260 int domainpolicy_db_ver(const str* db_url, const str* name)
00261 {
00262         int ver;
00263         db1_con_t* dbh;
00264 
00265         if (domainpolicy_dbf.init==0){
00266                 LM_CRIT("unbound database\n");
00267                 return -1;
00268         }
00269         dbh=domainpolicy_dbf.init(db_url);
00270         if (dbh==0){
00271                 LM_CRIT("null database handler\n");
00272                 return -1;
00273         }
00274         ver=db_table_version(&domainpolicy_dbf, dbh, name);
00275         domainpolicy_dbf.close(dbh);
00276         return ver;
00277 }
00278 
00279 /***************************/
00280 /*
00281  *
00282  * code from enum.c
00283  *
00284  * should be moved to some DDDS support module instead of code-duplication
00285  *
00286  *
00287  */
00288 
00289 /* Parse NAPTR regexp field of the form !pattern!replacement! and return its
00290  * components in pattern and replacement parameters.  Regexp field starts at
00291  * address first and is len characters long.
00292  */
00293 static inline int parse_naptr_regexp(char* first, int len, str* pattern,
00294                                                                                 str* replacement)
00295 {
00296         char *second, *third;
00297 
00298         if (len > 0) {
00299                 if (*first == '!') {
00300                         second = (char *)memchr((void *)(first + 1), '!', len - 1);
00301                         if (second) {
00302                                 len = len - (second - first + 1);
00303                                 if (len > 0) {
00304                                         third = memchr(second + 1, '!', len);
00305                                         if (third) {
00306                                                 pattern->len = second - first - 1;
00307                                                 pattern->s = first + 1;
00308                                                 replacement->len = third - second - 1;
00309                                                 replacement->s = second + 1;
00310                                                 return 1;
00311                                         } else {
00312                                                 LM_ERR("third ! missing from regexp\n");
00313                                                 return -1;
00314                                         }
00315                                 } else {
00316                                         LM_ERR("third ! missing from regexp\n");
00317                                         return -2;
00318                                 }
00319                         } else {
00320                                 LM_ERR("second ! missing from regexp\n");
00321                                 return -3;
00322                         }
00323                 } else {
00324                         LM_ERR("first ! missing from regexp\n");
00325                         return -4;
00326                 }
00327         } else {
00328                 LM_ERR("regexp missing\n");
00329                 return -5;
00330         }
00331 }
00332 
00333 
00334 /*
00335  * Tests if one result record is "greater" that the other.  Non-NAPTR records
00336  * greater that NAPTR record.  An invalid NAPTR record is greater than a 
00337  * valid one.  Valid NAPTR records are compared based on their
00338  * (order,preference).
00339  *
00340  * Naptrs without D2P+SIP service field are greater.
00341  *
00342  */
00343 static inline int naptr_greater(struct rdata* a, struct rdata* b)
00344 {
00345         struct naptr_rdata *na, *nb;
00346 
00347         if (a->type != T_NAPTR) return 1;
00348         if (b->type != T_NAPTR) return 0;
00349 
00350         na = (struct naptr_rdata*)a->rdata;
00351         if (na == 0) return 1;
00352 
00353         nb = (struct naptr_rdata*)b->rdata;
00354         if (nb == 0) return 0;
00355 
00356         if (!IS_D2PNAPTR(na))
00357                 return 1;
00358         
00359         if (!IS_D2PNAPTR(nb))
00360                 return 0;
00361 
00362         
00363         return (((na->order) << 16) + na->pref) >
00364                 (((nb->order) << 16) + nb->pref);
00365 }
00366         
00367         
00368 /*
00369  * Bubble sorts result record list according to naptr (order,preference).
00370  */
00371 static inline void naptr_sort(struct rdata** head)
00372 {
00373         struct rdata *p, *q, *r, *s, *temp, *start;
00374 
00375         /* r precedes p and s points to the node up to which comparisons
00376          are to be made */ 
00377 
00378         s = NULL;
00379         start = *head;
00380         while ( s != start -> next ) { 
00381                 r = p = start ; 
00382                 q = p -> next ;
00383                 while ( p != s ) { 
00384                         if ( naptr_greater(p, q) ) { 
00385                                 if ( p == start ) { 
00386                                         temp = q -> next ; 
00387                                         q -> next = p ; 
00388                                         p -> next = temp ;
00389                                         start = q ; 
00390                                         r = q ; 
00391                                 } else {
00392                                         temp = q -> next ; 
00393                                         q -> next = p ; 
00394                                         p -> next = temp ;
00395                                         r -> next = q ; 
00396                                         r = q ; 
00397                                 } 
00398                         } else {
00399                                 r = p ; 
00400                                 p = p -> next ; 
00401                         } 
00402                         q = p -> next ; 
00403                         if ( q == s ) s = p ; 
00404                 }
00405         }
00406         *head = start;
00407 }       
00408 
00409 /*
00410  * input: rule straight from the DDDS + avp-stack.
00411  *
00412  * output: adds found rules to the stack and return
00413  *      1 on success
00414  *      0 on failure
00415  */
00416 static int check_rule(str *rule, char *service, int service_len, struct avp_stack *stack) {
00417 
00418     /* for the select */
00419     db_key_t keys[2];
00420     db_val_t vals[2];
00421     db_key_t cols[4]; 
00422     db1_res_t* res;
00423     db_row_t* row;
00424     db_val_t* val;
00425     int i;
00426     char *type;
00427     int type_len;
00428 
00429     LM_INFO("checking for '%.*s'.\n", rule->len, ZSW(rule->s));
00430 
00431     if ((service_len != 11) || (strncasecmp("d2p+sip:fed", service, 11) && 
00432             strncasecmp("d2p+sip:std", service, 11)  && strncasecmp("d2p+sip:dom", service, 11))) {
00433         LM_ERR("can only cope with d2p+sip:fed, d2p+sip:std,and d2p+sip:dom "
00434                                 "for now (and not %.*s).\n", service_len, service);
00435         return(0);
00436     }
00437 
00438     type = service + 8;
00439     type_len = service_len - 8;
00440 
00441     if (domainpolicy_dbf.use_table(db_handle, &domainpolicy_table) < 0) {
00442             LM_ERR("failed to domainpolicy table\n");
00443             return -1;
00444     }
00445 
00446     keys[0]=&domainpolicy_col_rule;
00447     keys[1]=&domainpolicy_col_type;
00448     cols[0]=&domainpolicy_col_rule;
00449     cols[1]=&domainpolicy_col_type;
00450     cols[2]=&domainpolicy_col_att;
00451     cols[3]=&domainpolicy_col_val;
00452 
00453     VAL_TYPE(&vals[0]) = DB1_STR;
00454     VAL_NULL(&vals[0]) = 0;
00455     VAL_STR(&vals[0]).s = rule->s;
00456     VAL_STR(&vals[0]).len = rule->len;
00457 
00458     VAL_TYPE(&vals[1]) = DB1_STR;
00459     VAL_NULL(&vals[1]) = 0;
00460     VAL_STR(&vals[1]).s = type;
00461     VAL_STR(&vals[1]).len = type_len;
00462 
00463     /*
00464      * SELECT rule, att, val from domainpolicy where rule = "..."
00465      */
00466 
00467     if (domainpolicy_dbf.query(db_handle, keys, 0, vals, cols, 2, 4, 0, &res) < 0
00468                     ) {
00469             LM_ERR("querying database\n");
00470             return -1;
00471     }
00472     
00473     LM_INFO("querying database OK\n");
00474 
00475     if (RES_ROW_N(res) == 0) {
00476             LM_DBG("rule '%.*s' is not know.\n", 
00477                 rule->len, ZSW(rule->s));
00478             domainpolicy_dbf.free_result(db_handle, res);
00479             return 0;
00480     } else {
00481             LM_DBG("rule '%.*s' is known\n", rule->len, ZSW(rule->s));
00482 
00483             row = RES_ROWS(res);
00484 
00485             for(i = 0; i < RES_ROW_N(res); i++) {
00486                         if (ROW_N(row + i) != 4) {
00487                     LM_ERR("unexpected cell count\n");
00488                                 return(-1);
00489                         }
00490 
00491                         val = ROW_VALUES(row + i);
00492 
00493                         if ((VAL_TYPE(val) != DB1_STRING) || 
00494                                 (VAL_TYPE(val+1) != DB1_STRING) ||
00495                                 (VAL_TYPE(val+2) != DB1_STRING) ||
00496                                 (VAL_TYPE(val+3) != DB1_STRING)) {
00497                                         LM_ERR("unexpected cell types\n");
00498                             return(-1);
00499                         }
00500 
00501                         if (VAL_NULL(val+2) || VAL_NULL(val+3)) {
00502                                 LM_INFO("db returned NULL values. Fine with us.\n");
00503                                 continue;
00504                         }
00505 
00506                         LM_INFO("DB returned %s/%s \n",VAL_STRING(val+2),VAL_STRING(val+3));
00507 
00508 
00509                         if (!stack_push(stack, (char *) VAL_STRING(val+2), 
00510                                         (char *) VAL_STRING(val+3))) {
00511                             return(-1);
00512                         }
00513             }
00514             domainpolicy_dbf.free_result(db_handle, res);
00515             return 1;
00516     }
00517 }
00518 
00519 int dp_can_connect_str(str *domain, int rec_level) {
00520     struct rdata* head;
00521     struct rdata* l;
00522     struct naptr_rdata* naptr;
00523     struct naptr_rdata* next_naptr;
00524     int    ret;
00525     str    newdomain;
00526     char   uri[MAX_URI_SIZE];
00527     struct avp_stack stack;
00528     int    last_order = -1;
00529     int    failed = 0;
00530     int    found_anything = 0;
00531 
00532     str pattern, replacement, result;
00533 
00534     stack_reset(&stack);
00535     /* If we're in a recursive call, set the domain-replacement */
00536     if ( rec_level > 0 ) {
00537         stack_push(&stack, domain_replacement_name.s.s, domain->s);
00538         stack.succeeded = 0;
00539     }
00540 
00541     if (rec_level > MAX_DDDS_RECURSIONS) {
00542         LM_ERR("too many indirect NAPTRs. Aborting at %.*s.\n", domain->len,
00543                                 ZSW(domain->s));
00544                 return(DP_DDDS_RET_DNSERROR);
00545     }
00546 
00547     LM_INFO("looking up Domain itself: %.*s\n",domain->len, ZSW(domain->s));
00548     ret = check_rule(domain,"D2P+sip:dom", 11, &stack);
00549 
00550     if (ret == 1) {
00551         LM_INFO("found a match on domain itself\n");
00552         stack_to_avp(&stack);
00553         return(DP_DDDS_RET_POSITIVE);
00554     } else if (ret == 0) {
00555         LM_INFO("no match on domain itself.\n");
00556         stack_reset(&stack);
00557         /* If we're in a recursive call, set the domain-replacement */
00558         if ( rec_level > 0 ) {
00559             stack_push(&stack, domain_replacement_name.s.s, (char *) domain->s);
00560             stack.succeeded = 0;
00561         }
00562     } else {
00563         return(DP_DDDS_RET_DNSERROR);   /* actually: DB error */
00564     }
00565 
00566     LM_INFO("doing DDDS with %.*s\n",domain->len, ZSW(domain->s));
00567     head = get_record(domain->s, T_NAPTR, RES_ONLY_TYPE);
00568     if (head == 0) {
00569         LM_NOTICE("no NAPTR record found for %.*s.\n", 
00570                                 domain->len, ZSW(domain->s));
00571         return(DP_DDDS_RET_NOTFOUND);
00572     }
00573 
00574     LM_DBG("found the following NAPTRs: \n");
00575     for (l = head; l; l = l->next) {
00576         if (l->type != T_NAPTR) {
00577             LM_DBG("found non-NAPTR record.\n");
00578             continue; /*should never happen*/
00579         }
00580         naptr = (struct naptr_rdata*)l->rdata;
00581         if (naptr == 0) {
00582                 LM_CRIT("null rdata\n");
00583                 continue;
00584         }
00585         LM_DBG("order %u, pref %u, flen %u, flags '%.*s', slen %u, "
00586             "services '%.*s', rlen %u, regexp '%.*s', repl '%s'\n", 
00587                 naptr->order, naptr->pref,
00588             naptr->flags_len, (int)(naptr->flags_len), ZSW(naptr->flags),
00589             naptr->services_len,
00590             (int)(naptr->services_len), ZSW(naptr->services), naptr->regexp_len,
00591             (int)(naptr->regexp_len), ZSW(naptr->regexp),
00592             ZSW(naptr->repl)
00593             );
00594     }
00595 
00596 
00597     LM_DBG("sorting...\n");
00598     naptr_sort(&head);
00599 
00600     for (l = head; l; l = l->next) {
00601 
00602         if (l->type != T_NAPTR) continue; /*should never happen*/
00603         naptr = (struct naptr_rdata*)l->rdata;
00604         if (naptr == 0) {
00605                 LM_CRIT("null rdata\n");
00606                 continue;
00607         }
00608 
00609         LM_DBG("considering order %u, pref %u, flen %u, flags '%.*s', slen %u, "
00610             "services '%.*s', rlen %u, regexp '%.*s', repl '%s'\n", 
00611                 naptr->order, naptr->pref,
00612             naptr->flags_len, (int)(naptr->flags_len), ZSW(naptr->flags),
00613             naptr->services_len,
00614             (int)(naptr->services_len), ZSW(naptr->services), naptr->regexp_len,
00615             (int)(naptr->regexp_len), ZSW(naptr->regexp),
00616             ZSW(naptr->repl)
00617             );
00618 
00619         /*
00620          * New order? then we check whether the had success during the last one.
00621          * If yes, we can leave the loop.
00622          */
00623         if (last_order != naptr->order) {
00624                 last_order = naptr->order;
00625                 failed = 0;
00626 
00627                 if (stack_succeeded(&stack)) {
00628                 LM_INFO("we don't need to consider further orders "
00629                                                 "(starting with %d).\n",last_order);
00630                     break;
00631                 }
00632         } else if (failed) {
00633             LM_INFO("order %d has already failed.\n",last_order);
00634             continue;
00635         }
00636 
00637 
00638         /*
00639          * NAPTRs we don't care about
00640          */
00641         if (!IS_D2PNAPTR(naptr)) 
00642             continue;
00643 
00644         /*
00645          * once we've been here, don't return DP_DDDS_RET_NOTFOUND
00646          */
00647         found_anything = 1;
00648 
00649         next_naptr = NULL;
00650         if (l->next && (l->next->type == T_NAPTR)) {
00651              next_naptr = (struct naptr_rdata*)l->next->rdata;
00652         }
00653 
00654         /*
00655          * Non-terminal?
00656          */
00657         if ((naptr->services_len == 7) && !strncasecmp("D2P+SIP", naptr->services,7) && (naptr->flags_len == 0)){
00658             LM_INFO("found non-terminal NAPTR\n");
00659 
00660             /*
00661              * This needs to be the only record with this order.
00662              */
00663             if (next_naptr && (next_naptr->order == naptr->order) && IS_D2PNAPTR(next_naptr)) {
00664                 LM_ERR("non-terminal NAPTR needs to be the only one "
00665                                         "with this order %.*s.\n", domain->len, ZSW(domain->s));
00666 
00667                 return(DP_DDDS_RET_DNSERROR);
00668             }
00669 
00670             newdomain.s = naptr->repl;
00671             newdomain.len = strlen(naptr->repl);
00672 
00673             ret = dp_can_connect_str(&newdomain, rec_level + 1);
00674 
00675             if (ret == DP_DDDS_RET_POSITIVE)    /* succeeded, we're done. */
00676                 return(ret);
00677 
00678             if (ret == DP_DDDS_RET_NEGATIVE)    /* found rules, did not work */
00679                 continue;                       /* look for more rules */
00680 
00681             if (ret == DP_DDDS_RET_DNSERROR)    /* errors during lookup */
00682                 return(ret);                    /* report them */
00683 
00684             if (ret == DP_DDDS_RET_NOTFOUND)    /* no entries in linked domain? */
00685                 return(ret);                    /* ok, fine. go with that */
00686 
00687             continue; /* not reached */
00688         }
00689 
00690         /*
00691          * wrong kind of terminal
00692          */
00693         if ((naptr->flags_len != 1) || (tolower(naptr->flags[0]) != 'u')) {
00694             LM_ERR("terminal NAPTR needs flag = 'u' and not '%.*s'.\n",
00695                                         (int)naptr->flags_len, ZSW(naptr->flags));
00696                 /*
00697                  * It's not that clear what we should do now: Ignore this records or regard it as failed.
00698                  * We go with "ignore" for now.
00699                  */
00700                 continue;
00701         }
00702 
00703         if (parse_naptr_regexp(&(naptr->regexp[0]), naptr->regexp_len,
00704                                &pattern, &replacement) < 0) {
00705                 LM_ERR("parsing of NAPTR regexp failed\n");
00706                 continue;
00707         }
00708         result.s = &(uri[0]);
00709         result.len = MAX_URI_SIZE;
00710 
00711         /* Avoid making copies of pattern and replacement */
00712         pattern.s[pattern.len] = (char)0;
00713         replacement.s[replacement.len] = (char)0;
00714         if (reg_replace(pattern.s, replacement.s, domain->s,
00715                         &result) < 0) {
00716                 pattern.s[pattern.len] = '!';
00717                 replacement.s[replacement.len] = '!';
00718                 LM_ERR("regexp replace failed\n");
00719                 continue;
00720         }
00721         LM_INFO("resulted in replacement: '%.*s'\n", result.len, ZSW(result.s));
00722         pattern.s[pattern.len] = '!';
00723         replacement.s[replacement.len] = '!';
00724 
00725         ret = check_rule(&result,naptr->services,naptr->services_len, &stack);
00726 
00727         if (ret == 1) {
00728             LM_INFO("positive return\n");
00729         } else if (ret == 0) {
00730             LM_INFO("check_rule failed.\n");
00731             stack_reset(&stack);
00732             /* If we're in a recursive call, set the domain-replacement */
00733             if ( rec_level > 0 ) {
00734                 stack_push(&stack, domain_replacement_name.s.s, (char *) domain->s);
00735                 stack.succeeded = 0;
00736             }
00737             failed = 1;
00738         } else {
00739             return(DP_DDDS_RET_DNSERROR);
00740         }
00741     }
00742 
00743     if (stack_succeeded(&stack)) {
00744         LM_INFO("calling stack_to_avp.\n");
00745                 stack_to_avp(&stack);
00746                 return(DP_DDDS_RET_POSITIVE);
00747     }
00748 
00749     LM_INFO("returning %d.\n", 
00750             (found_anything ? DP_DDDS_RET_NEGATIVE : DP_DDDS_RET_NOTFOUND));
00751     return(  found_anything ? DP_DDDS_RET_NEGATIVE : DP_DDDS_RET_NOTFOUND );
00752 }
00753 
00754 
00762 int dp_can_connect(struct sip_msg* _msg, char* _s1, char* _s2) {
00763 
00764         static char domainname[MAX_DOMAIN_SIZE];
00765         str domain;
00766         int ret;
00767 
00768         if (!is_route_type(REQUEST_ROUTE)) {
00769                 LM_ERR("unsupported route type\n");
00770                 return -1;
00771         }
00772 
00773         if (parse_sip_msg_uri(_msg) < 0) {
00774                 LM_ERR("failed to parse R-URI\n");
00775                 return -1;
00776         }
00777 
00778         if (_msg->parsed_uri.host.len >= MAX_DOMAIN_SIZE) {
00779                 LM_ERR("domain buffer to small\n");
00780                 return -1;
00781         }
00782 
00783         /* copy domain into static buffer as later we sometimes need \0
00784          * terminated strings
00785          */
00786         domain.s = (char *) &(domainname[0]);
00787         domain.len = _msg->parsed_uri.host.len;
00788         memcpy(domain.s, _msg->parsed_uri.host.s, domain.len);
00789         domainname[domain.len] = '\0';
00790 
00791         LM_DBG("domain is %.*s.\n", domain.len, ZSW(domain.s));
00792 
00793         ret = dp_can_connect_str(&domain,0);
00794         LM_DBG("returning %d.\n", ret);
00795         return(ret);
00796 }
00797 
00798 
00811 int dp_apply_policy(struct sip_msg* _msg, char* _s1, char* _s2) {
00812 
00813         str *domain;
00814         int_str val;
00815         struct usr_avp *avp;
00816 
00817         char duri[MAX_URI_SIZE];
00818         str duri_str;
00819         int len, didsomething;
00820         char *at; /* pointer to current location inside duri */
00821 
00822         str host;
00823         int port, proto;
00824         struct socket_info* si;
00825 
00826         if (!is_route_type(REQUEST_ROUTE)) {
00827                 LM_ERR("unsupported route type\n");
00828                 return -1;
00829         }
00830 
00831         /*
00832          * set the send_socket
00833          */
00834 
00835         /* search for send_socket AVP */
00836         avp = search_first_avp(send_socket_avp_name_str, send_socket_name, &val, 0);
00837         if (avp) {
00838                 if ( !(avp->flags&AVP_VAL_STR) ||  !val.s.s || !val.s.len) {
00839                         LM_ERR("empty or non-string send_socket_avp, "
00840                                         "return with error ...\n");
00841                         return -1;
00842                 }
00843                 LM_DBG("send_socket_avp found = '%.*s'\n", val.s.len, ZSW(val.s.s));
00844                 /* parse phostport - AVP str val is asciiz */
00845                 /* FIXME: This code relies on the fact that the string value of an AVP
00846                  * is zero terminated, which may or may not be true in the future */
00847                 if (parse_phostport(val.s.s, &(host.s), &(host.len), &port, &proto)) {
00848                         LM_ERR("could not parse send_socket, return with error ...\n");
00849                         return -1;
00850                 }
00851                 si = grep_sock_info( &host, (unsigned short) port, (unsigned short) proto);
00852                 if (si) {
00853                         set_force_socket(_msg, si);
00854                 } else {
00855                         LM_WARN("could not find socket for"
00856                                         "send_socket '%.*s'\n", val.s.len, ZSW(val.s.s));
00857                 }
00858         } else {
00859                 LM_DBG("send_socket_avp not found\n");
00860         }
00861 
00862         /*
00863          * set the destination URI
00864          */
00865 
00866         didsomething = 0; /* if no AVP is set, there is no need to set the DURI in the end */
00867         
00868         if (parse_sip_msg_uri(_msg) < 0) {
00869                 LM_ERR("failed to parse R-URI\n");
00870                 return -1;
00871         }
00872 
00873         at = (char *)&(duri[0]);
00874         len = 0;
00875         if ( (len + 4) >  MAX_URI_SIZE) {
00876                 LM_ERR("duri buffer to small to add uri schema\n");
00877                 return -1;
00878         }
00879         memcpy(at, "sip:", 4); at = at + 4; len = len + 4;
00880 
00881         domain = &(_msg->parsed_uri.host);
00882         LM_DBG("domain is %.*s.\n", domain->len, ZSW(domain->s));
00883 
00884         /* search for prefix and add it to duri buffer */
00885         avp = search_first_avp(domain_prefix_avp_name_str, domain_prefix_name, &val, 0);
00886         if (avp) {
00887                 if ( !(avp->flags&AVP_VAL_STR) ||  !val.s.s || !val.s.len) {
00888                         LM_ERR("empty or non-string domain_prefix_avp, return with error ...\n");
00889                         return -1;
00890                 }
00891                 LM_DBG("domain_prefix_avp found = '%.*s'\n", val.s.len, ZSW(val.s.s));
00892                 if ( (len + val.s.len +1) >  MAX_URI_SIZE) {
00893                         LM_ERR("duri buffer to small to add domain prefix\n");
00894                         return -1;
00895                 }
00896                 memcpy(at, val.s.s, val.s.len); at = at + val.s.len;
00897                 *at = '.'; at = at + 1; /* add . as delimiter between prefix and domain */
00898                 didsomething = 1;
00899         } else {
00900                 LM_DBG("domain_prefix_avp not found\n");
00901         }
00902 
00903 
00904         /* add domain to duri buffer */
00905         avp = search_first_avp(domain_replacement_avp_name_str, domain_replacement_name, &val, 0);
00906         if (avp) {
00907                 if ( !(avp->flags&AVP_VAL_STR) ||  !val.s.s || !val.s.len) {
00908                         LM_ERR("empty or non-string domain_replacement_avp, return with"
00909                                         "error ...\n");
00910                         return -1;
00911                 }
00912                 LM_DBG("domain_replacement_avp found='%.*s'\n",val.s.len, ZSW(val.s.s));
00913                 if ( (len + val.s.len +1) >  MAX_URI_SIZE) {
00914                         LM_ERR("duri buffer to small to add domain replacement\n");
00915                         return -1;
00916                 }
00917                 memcpy(at, val.s.s, val.s.len); at = at + val.s.len;
00918                 didsomething = 1;
00919         } else {
00920             LM_DBG("domain_replacement_avp not found, using original domain '"
00921                                 "%.*s'\n",domain->len, domain->s);
00922             if ( (len + domain->len) >  MAX_URI_SIZE) {
00923                 LM_ERR("duri buffer to small to add domain\n");
00924                 return -1;
00925             }
00926             memcpy(at, domain->s, domain->len); at = at + domain->len;
00927         }
00928         
00929         /* search for suffix and add it to duri buffer */
00930         avp = search_first_avp(domain_suffix_avp_name_str, domain_suffix_name, &val, 0);
00931         if (avp) {
00932                 if ( !(avp->flags&AVP_VAL_STR) ||  !val.s.s || !val.s.len) {
00933                         LM_ERR("empty or non-string domain_suffix_avp,return with error .."
00934                                         "\n");
00935                         return -1;
00936                 }
00937                 LM_DBG("domain_suffix_avp found = '%.*s'\n", val.s.len, ZSW(val.s.s));
00938                 if ( (len + val.s.len + 1) >  MAX_URI_SIZE) {
00939                         LM_ERR("duri buffer to small to add domain suffix\n");
00940                         return -1;
00941                 }
00942                 *at = '.'; at = at + 1; /* add . as delimiter between domain and suffix */
00943                 memcpy(at, val.s.s, val.s.len); at = at + val.s.len;
00944                 didsomething = 1;
00945         } else {
00946                 LM_DBG("domain_suffix_avp not found\n");
00947         }
00948 
00949         /* search for port override and add it to duri buffer */
00950         avp = search_first_avp(port_override_avp_name_str, port_override_name, &val, 0);
00951         if (avp) {
00952                 if ( !(avp->flags&AVP_VAL_STR) ||  !val.s.s || !val.s.len) {
00953                         LM_ERR("empty or non-string port_override_avp, return with error ...\n");
00954                         return -1;
00955                 }
00956                 LM_DBG("port_override_avp found = '%.*s'\n", val.s.len, ZSW(val.s.s));
00957                 /* We do not check if the port is valid */
00958                 if ( (len + val.s.len + 1) >  MAX_URI_SIZE) {
00959                         LM_ERR("duri buffer to small to add domain suffix\n");
00960                         return -1;
00961                 }
00962                 *at = ':'; at = at + 1; /* add : as delimiter between domain and port */
00963                 memcpy(at, val.s.s, val.s.len); at = at + val.s.len;
00964                 didsomething = 1;
00965         } else {
00966                 LM_DBG("port_override_avp not found, using original port\n");
00967                 if (_msg->parsed_uri.port.len) {
00968                         LM_DBG("port found in RURI, reusing it for DURI\n");
00969                         if ( (len + _msg->parsed_uri.port.len + 1) >  MAX_URI_SIZE) {
00970                                 LM_ERR("duri buffer to small to copy port\n");
00971                                 return -1;
00972                         }
00973                         *at = ':'; at = at + 1; 
00974                         /* add : as delimiter between domain and port */
00975                         memcpy(at, _msg->parsed_uri.port.s, _msg->parsed_uri.port.len); 
00976                         at = at + _msg->parsed_uri.port.len;
00977                 } else {
00978                         LM_DBG("port not found in RURI, no need to copy it to DURI\n");
00979                 }
00980         }
00981 
00982         /* search for transport override and add it to duri buffer */
00983         avp = search_first_avp(transport_override_avp_name_str, transport_override_name, &val, 0);
00984         if (avp) {
00985                 if ( !(avp->flags&AVP_VAL_STR) ||  !val.s.s || !val.s.len) {
00986                         LM_ERR("empty or non-string transport_override_avp, "
00987                                         "return with error ...\n");
00988                         return -1;
00989                 }
00990                 LM_DBG("transport_override_avp found='%.*s'\n",val.s.len, ZSW(val.s.s));
00991 
00992                 if ( (len + val.s.len + 11) >  MAX_URI_SIZE) {
00993                         LM_ERR("duri buffer to small to add transport override\n");
00994                         return -1;
00995                 }
00996                 /* add : as transport parameter to duri; NOTE: no checks if transport parameter is valid  */
00997                 memcpy(at, ";transport=", 11); at = at + 11;
00998                 memcpy(at, val.s.s, val.s.len); at = at + val.s.len;
00999                 didsomething = 1;
01000         } else {
01001                 LM_DBG("transport_override_avp not found, using original transport\n");
01002                 if (_msg->parsed_uri.transport.len) {
01003                         LM_DBG("transport found in RURI, reusing it for DURI\n");
01004                         if ( (len + _msg->parsed_uri.transport.len + 1) >  MAX_URI_SIZE) {
01005                                 LM_ERR("duri buffer to small to copy transport\n");
01006                                 return -1;
01007                         }
01008                         *at = ';'; at = at + 1; /* add : as delimiter between domain and port */
01009                         memcpy(at, _msg->parsed_uri.transport.s, _msg->parsed_uri.transport.len); at = at + _msg->parsed_uri.transport.len;
01010                 } else {
01011                         LM_DBG("transport not found in RURI, no need to copy it to DURI\n");
01012                 }
01013         }
01014 
01015         /* write new target DURI into DURI */
01016         if (didsomething == 0) {
01017                 LM_DBG("no domainpolicy AVP set, no need to push new DURI\n");
01018                 return 2;
01019         }
01020         duri_str.s = (char *)&(duri[0]);
01021         duri_str.len = at - duri_str.s;
01022         LM_DBG("new DURI is '%.*s'\n",duri_str.len, ZSW(duri_str.s));
01023         set_dst_uri(_msg, &duri_str);
01024         /* dst_uri changes, so it makes sense to re-use the current uri for
01025                 forking */
01026         ruri_mark_new(); /* re-use uri for serial forking */
01027 
01028         return 1;
01029 }
01030