domainpolicy.c

Go to the documentation of this file.
00001 /* 
00002  * $Id: domainpolicy.c 5695 2009-03-12 23:22:18Z henningw $
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 
00031 /*!
00032  * \file
00033  * \brief Domain Policy related functions
00034  */
00035 
00036 
00037 #include "domainpolicy_mod.h"
00038 #include "domainpolicy.h"
00039 #include "../../db/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 "../../regexp.h"
00050 
00051 #define IS_D2PNAPTR(naptr) ((naptr->services_len >= 7) && (!strncasecmp("D2P+SIP", naptr->services, 7)))
00052 
00053 static db_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 
00204 /*!
00205  * \brief Bind the database interface
00206  * \param db_url database url
00207  * \return -1 on failure, 0 on success
00208  */
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 
00220 /*!
00221  * \brief Initialize the database connection
00222  * \param db_url database url
00223  * \return -1 on failure, 0 on success
00224  */
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 
00242 /*!
00243  * \brief Close the database connection
00244  */
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 
00254 /*!
00255  * \brief Check the database table version
00256  * \param db_url database URL
00257  * \param name table name
00258  * \return -1 on failure, positive database version on success
00259  */
00260 int domainpolicy_db_ver(const str* db_url, const str* name)
00261 {
00262    int ver;
00263    db_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     db_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]) = DB_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]) = DB_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) != DB_STRING) || 
00494             (VAL_TYPE(val+1) != DB_STRING) ||
00495             (VAL_TYPE(val+2) != DB_STRING) ||
00496             (VAL_TYPE(val+3) != DB_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);
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 
00755 /*!
00756  * \brief Check if host in Request URI has DP-DDDS NAPTRs and if we can connect to them
00757  * \param _msg SIP message
00758  * \param _s1 unused
00759  * \param _s2 unused
00760  * \return negative on failure, positive on success
00761  */
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 (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 
00799 /*!
00800  * \brief Apply DP-DDDS policy to current SIP message
00801  *
00802  * Apply DP-DDDS policy to current SIP message. This means
00803  * build a new destination URI from the policy AVP and export it
00804  * as AVP. Then in kamailio.cfg this new target AVP can be pushed
00805  * into the destination URI $duri
00806  * \param _msg SIP message
00807  * \param _s1 unused
00808  * \param _s2 unused
00809  * \return negative on failure, positive on succes
00810  */
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 (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 */
00845       if (parse_phostport(val.s.s, val.s.len, &(host.s), &(host.len), &port, &proto)) {
00846          LM_ERR("could not parse send_socket, return with error ...\n");
00847          return -1;
00848       }
00849       si = grep_sock_info( &host, (unsigned short) port, (unsigned short) proto);
00850       if (si) {
00851          _msg->force_send_socket = si;
00852       } else {
00853          LM_WARN("could not find socket for"
00854                "send_socket '%.*s'\n", val.s.len, ZSW(val.s.s));
00855       }
00856    } else {
00857       LM_DBG("send_socket_avp not found\n");
00858    }
00859 
00860    /*
00861     * set the destination URI
00862     */
00863 
00864    didsomething = 0; /* if no AVP is set, there is no need to set the DURI in the end */
00865    
00866    if (parse_sip_msg_uri(_msg) < 0) {
00867       LM_ERR("failed to parse R-URI\n");
00868       return -1;
00869    }
00870 
00871    at = (char *)&(duri[0]);
00872    len = 0;
00873    if ( (len + 4) >  MAX_URI_SIZE) {
00874       LM_ERR("duri buffer to small to add uri schema\n");
00875       return -1;
00876    }
00877    memcpy(at, "sip:", 4); at = at + 4; len = len + 4;
00878 
00879    domain = &(_msg->parsed_uri.host);
00880    LM_DBG("domain is %.*s.\n", domain->len, ZSW(domain->s));
00881 
00882    /* search for prefix and add it to duri buffer */
00883    avp = search_first_avp(domain_prefix_avp_name_str, domain_prefix_name, &val, 0);
00884    if (avp) {
00885       if ( !(avp->flags&AVP_VAL_STR) ||  !val.s.s || !val.s.len) {
00886          LM_ERR("empty or non-string domain_prefix_avp, return with error ...\n");
00887          return -1;
00888       }
00889       LM_DBG("domain_prefix_avp found = '%.*s'\n", val.s.len, ZSW(val.s.s));
00890       if ( (len + val.s.len +1) >  MAX_URI_SIZE) {
00891          LM_ERR("duri buffer to small to add domain prefix\n");
00892          return -1;
00893       }
00894       memcpy(at, val.s.s, val.s.len); at = at + val.s.len;
00895       *at = '.'; at = at + 1; /* add . as delimiter between prefix and domain */
00896       didsomething = 1;
00897    } else {
00898       LM_DBG("domain_prefix_avp not found\n");
00899    }
00900 
00901 
00902    /* add domain to duri buffer */
00903    avp = search_first_avp(domain_replacement_avp_name_str, domain_replacement_name, &val, 0);
00904    if (avp) {
00905       if ( !(avp->flags&AVP_VAL_STR) ||  !val.s.s || !val.s.len) {
00906          LM_ERR("empty or non-string domain_replacement_avp, return with"
00907                "error ...\n");
00908          return -1;
00909       }
00910       LM_DBG("domain_replacement_avp found='%.*s'\n",val.s.len, ZSW(val.s.s));
00911       if ( (len + val.s.len +1) >  MAX_URI_SIZE) {
00912          LM_ERR("duri buffer to small to add domain replacement\n");
00913          return -1;
00914       }
00915       memcpy(at, val.s.s, val.s.len); at = at + val.s.len;
00916       didsomething = 1;
00917    } else {
00918        LM_DBG("domain_replacement_avp not found, using original domain '"
00919             "%.*s'\n",domain->len, domain->s);
00920        if ( (len + domain->len) >  MAX_URI_SIZE) {
00921       LM_ERR("duri buffer to small to add domain\n");
00922       return -1;
00923        }
00924        memcpy(at, domain->s, domain->len); at = at + domain->len;
00925    }
00926    
00927    /* search for suffix and add it to duri buffer */
00928    avp = search_first_avp(domain_suffix_avp_name_str, domain_suffix_name, &val, 0);
00929    if (avp) {
00930       if ( !(avp->flags&AVP_VAL_STR) ||  !val.s.s || !val.s.len) {
00931          LM_ERR("empty or non-string domain_suffix_avp,return with error .."
00932                "\n");
00933          return -1;
00934       }
00935       LM_DBG("domain_suffix_avp found = '%.*s'\n", val.s.len, ZSW(val.s.s));
00936       if ( (len + val.s.len + 1) >  MAX_URI_SIZE) {
00937          LM_ERR("duri buffer to small to add domain suffix\n");
00938          return -1;
00939       }
00940       *at = '.'; at = at + 1; /* add . as delimiter between domain and suffix */
00941       memcpy(at, val.s.s, val.s.len); at = at + val.s.len;
00942       didsomething = 1;
00943    } else {
00944       LM_DBG("domain_suffix_avp not found\n");
00945    }
00946 
00947    /* search for port override and add it to duri buffer */
00948    avp = search_first_avp(port_override_avp_name_str, port_override_name, &val, 0);
00949    if (avp) {
00950       if ( !(avp->flags&AVP_VAL_STR) ||  !val.s.s || !val.s.len) {
00951          LM_ERR("empty or non-string port_override_avp, return with error ...\n");
00952          return -1;
00953       }
00954       LM_DBG("port_override_avp found = '%.*s'\n", val.s.len, ZSW(val.s.s));
00955       /* We do not check if the port is valid */
00956       if ( (len + val.s.len + 1) >  MAX_URI_SIZE) {
00957          LM_ERR("duri buffer to small to add domain suffix\n");
00958          return -1;
00959       }
00960       *at = ':'; at = at + 1; /* add : as delimiter between domain and port */
00961       memcpy(at, val.s.s, val.s.len); at = at + val.s.len;
00962       didsomething = 1;
00963    } else {
00964       LM_DBG("port_override_avp not found, using original port\n");
00965       if (_msg->parsed_uri.port.len) {
00966          LM_DBG("port found in RURI, reusing it for DURI\n");
00967          if ( (len + _msg->parsed_uri.port.len + 1) >  MAX_URI_SIZE) {
00968             LM_ERR("duri buffer to small to copy port\n");
00969             return -1;
00970          }
00971          *at = ':'; at = at + 1; 
00972          /* add : as delimiter between domain and port */
00973          memcpy(at, _msg->parsed_uri.port.s, _msg->parsed_uri.port.len); 
00974          at = at + _msg->parsed_uri.port.len;
00975       } else {
00976          LM_DBG("port not found in RURI, no need to copy it to DURI\n");
00977       }
00978    }
00979 
00980    /* search for transport override and add it to duri buffer */
00981    avp = search_first_avp(transport_override_avp_name_str, transport_override_name, &val, 0);
00982    if (avp) {
00983       if ( !(avp->flags&AVP_VAL_STR) ||  !val.s.s || !val.s.len) {
00984          LM_ERR("empty or non-string transport_override_avp, "
00985                "return with error ...\n");
00986          return -1;
00987       }
00988       LM_DBG("transport_override_avp found='%.*s'\n",val.s.len, ZSW(val.s.s));
00989 
00990       if ( (len + val.s.len + 11) >  MAX_URI_SIZE) {
00991          LM_ERR("duri buffer to small to add transport override\n");
00992          return -1;
00993       }
00994       /* add : as transport parameter to duri; NOTE: no checks if transport parameter is valid  */
00995       memcpy(at, ";transport=", 11); at = at + 11;
00996       memcpy(at, val.s.s, val.s.len); at = at + val.s.len;
00997       didsomething = 1;
00998    } else {
00999       LM_DBG("transport_override_avp not found, using original transport\n");
01000       if (_msg->parsed_uri.transport.len) {
01001          LM_DBG("transport found in RURI, reusing it for DURI\n");
01002          if ( (len + _msg->parsed_uri.transport.len + 1) >  MAX_URI_SIZE) {
01003             LM_ERR("duri buffer to small to copy transport\n");
01004             return -1;
01005          }
01006          *at = ';'; at = at + 1; /* add : as delimiter between domain and port */
01007          memcpy(at, _msg->parsed_uri.transport.s, _msg->parsed_uri.transport.len); at = at + _msg->parsed_uri.transport.len;
01008       } else {
01009          LM_DBG("transport not found in RURI, no need to copy it to DURI\n");
01010       }
01011    }
01012 
01013    /* write new target DURI into DURI */
01014    if (didsomething == 0) {
01015       LM_DBG("no domainpolicy AVP set, no need to push new DURI\n");
01016       return 2;
01017    }
01018    duri_str.s = (char *)&(duri[0]);
01019    duri_str.len = at - duri_str.s;
01020    LM_DBG("new DURI is '%.*s'\n",duri_str.len, ZSW(duri_str.s));
01021    set_dst_uri(_msg, &duri_str);
01022 
01023    return 1;
01024 }
01025 

Generated on Tue May 22 16:00:27 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6