record.c

Go to the documentation of this file.
00001 /*
00002  * $Id: record.c 5575 2009-02-10 10:13:29Z henningw $
00003  *
00004  * Copyright (C) 2001-2003 FhG Fokus
00005  *
00006  * This file is part of Kamailio, a free SIP server.
00007  *
00008  * Kamailio is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version
00012  *
00013  * Kamailio is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License 
00019  * along with this program; if not, write to the Free Software 
00020  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  */
00022 
00023 /*!
00024  * \file
00025  * \brief Route & Record-Route module, loose routing support
00026  * \ingroup rr
00027  */
00028 
00029 /*!
00030  * \defgroup rr RR :: Route & Record-Route Module
00031  * This module contains record routing logic, as described in RFC 3261
00032  * (see chapter 16.12 and 12.1.1 - UAS behavior).
00033  */
00034 
00035 #include <string.h>
00036 #include "../../mem/mem.h"
00037 #include "../../dprint.h"
00038 #include "../../parser/parse_uri.h"
00039 #include "../../parser/parse_from.h"
00040 #include "../../str.h"
00041 #include "../../data_lump.h"
00042 #include "record.h"
00043 #include "rr_mod.h"
00044 
00045 
00046 #define RR_PREFIX "Record-Route: <sip:"
00047 #define RR_PREFIX_LEN (sizeof(RR_PREFIX)-1)
00048 
00049 #define RR_LR ";lr"
00050 #define RR_LR_LEN (sizeof(RR_LR)-1)
00051 
00052 #define RR_LR_FULL ";lr=on"
00053 #define RR_LR_FULL_LEN (sizeof(RR_LR_FULL)-1)
00054 
00055 #define RR_FROMTAG ";ftag="
00056 #define RR_FROMTAG_LEN (sizeof(RR_FROMTAG)-1)
00057 
00058 #define RR_R2 ";r2=on"
00059 #define RR_R2_LEN (sizeof(RR_R2)-1)
00060 
00061 #define RR_TERM ">"CRLF
00062 #define RR_TERM_LEN (sizeof(RR_TERM)-1)
00063 
00064 #define INBOUND  1   /*!< Insert inbound Record-Route */
00065 #define OUTBOUND 0   /*!< Insert outbound Record-Route */
00066 
00067 #define RR_PARAM_BUF_SIZE 512 /*!< buffer for RR parameter */
00068 
00069 
00070 /*!
00071  * \brief RR param buffer 
00072  * \note used for storing RR param which are added before RR insertion
00073  */
00074 static char rr_param_buf_ptr[RR_PARAM_BUF_SIZE];
00075 static str rr_param_buf = {rr_param_buf_ptr,0};
00076 static unsigned int rr_param_msg;
00077 
00078 
00079 /*!
00080  * \brief Extract username from the Request URI
00081  *
00082  * Extract username from the Request URI. First try to look at the original
00083  * Request URI and if there is no username use the new Request URI.
00084  * \param _m SIP message
00085  * \param _user username
00086  * \return 0 on success, negative on errors
00087  */
00088 static inline int get_username(struct sip_msg* _m, str* _user)
00089 {
00090    struct sip_uri puri;
00091 
00092         /* first try to look at r-uri for a username */
00093    if (parse_uri(_m->first_line.u.request.uri.s, _m->first_line.u.request.uri.len, &puri) < 0) {
00094       LM_ERR("failed to parse R-URI\n");
00095       return -1;
00096    }
00097 
00098    /* no username in original uri -- hmm; maybe it is a uri
00099     * with just host address and username is in a preloaded route,
00100     * which is now no rewritten r-uri (assumed rewriteFromRoute
00101     * was called somewhere in script's beginning) 
00102     */
00103    if (!puri.user.len && _m->new_uri.s) {
00104       if (parse_uri(_m->new_uri.s, _m->new_uri.len, &puri) < 0) {
00105          LM_ERR("failed to parse new_uri\n");
00106          return -2;
00107            }
00108    }
00109 
00110    _user->s = puri.user.s;
00111    _user->len = puri.user.len;
00112    return 0;
00113 }
00114 
00115 
00116 /*!
00117  * \brief Insert RR parameter lump in new allocated private memory
00118  * \param before lump list
00119  * \param s parameter string
00120  * \param l parameter string length
00121  * \return pointer to new lump on success, NULL on failure
00122  */
00123 static inline struct lump *insert_rr_param_lump(struct lump *before,
00124                   char *s, int l)
00125 {
00126    struct lump *rrp_l;
00127    char *s1;
00128 
00129    /* duplicate data in pkg mem */
00130    s1 = (char*)pkg_malloc(l);
00131    if (s1==0) {
00132       LM_ERR("no more pkg mem (%d)\n",l);
00133       return 0;
00134    }
00135    memcpy( s1, s, l);
00136 
00137    /* add lump */
00138    rrp_l = insert_new_lump_before( before, s1, l, HDR_RECORDROUTE_T);
00139    if (rrp_l==0) {
00140       LM_ERR("failed to add before lump\n");
00141       pkg_free(s1);
00142       return 0;
00143    }
00144    return rrp_l;
00145 }
00146 
00147 
00148 /*!
00149  * \brief Build a Record-Route header field
00150  *
00151 * Build a Record-Route header field, allocates new private memory for this.
00152  * \param _l first lump
00153  * \param _l2 second lump
00154  * \param tag tag parameter
00155  * \param params parameter
00156  * \param _inbound inbound request
00157  * \return 0 on success, negative on failure
00158  */
00159 static inline int build_rr(struct lump* _l, struct lump* _l2, str* user,
00160                   str *tag, str *params, int _inbound)
00161 {
00162    char* prefix, *suffix, *term, *r2;
00163    int suffix_len, prefix_len;
00164    char *p;
00165 
00166    prefix_len = RR_PREFIX_LEN + (user->len ? (user->len + 1) : 0);
00167    if (enable_full_lr) {
00168       suffix_len = RR_LR_FULL_LEN + (params?params->len:0) +
00169             ((tag && tag->len) ? (RR_FROMTAG_LEN + tag->len) : 0);
00170    } else {
00171       suffix_len = RR_LR_LEN + (params?params->len:0) +
00172             ((tag && tag->len) ? (RR_FROMTAG_LEN + tag->len) : 0);
00173    }
00174 
00175    prefix = pkg_malloc(prefix_len);
00176    suffix = pkg_malloc(suffix_len);
00177    term = pkg_malloc(RR_TERM_LEN);
00178    r2 = pkg_malloc(RR_R2_LEN);
00179 
00180    if (!prefix || !suffix || !term || !r2) {
00181       LM_ERR("No more pkg memory\n");
00182       if (suffix) pkg_free(suffix);
00183       if (prefix) pkg_free(prefix);
00184       if (term) pkg_free(term);
00185       if (r2) pkg_free(r2);
00186       return -3;
00187    }
00188    
00189    memcpy(prefix, RR_PREFIX, RR_PREFIX_LEN);
00190    if (user->len) {
00191       memcpy(prefix + RR_PREFIX_LEN, user->s, user->len);
00192 #ifdef ENABLE_USER_CHECK
00193       /* don't add the ignored user into a RR */
00194       if(i_user.len && i_user.len == user->len && 
00195             !strncmp(i_user.s, user->s, i_user.len))
00196       {
00197          if(prefix[RR_PREFIX_LEN]=='x')
00198             prefix[RR_PREFIX_LEN]='y';
00199          else
00200             prefix[RR_PREFIX_LEN]='x';
00201       }
00202 #endif
00203       prefix[RR_PREFIX_LEN + user->len] = '@';
00204    }
00205 
00206    p = suffix;
00207    if (enable_full_lr) {
00208       memcpy( p, RR_LR_FULL, RR_LR_FULL_LEN);
00209       p += RR_LR_FULL_LEN;
00210    } else {
00211       memcpy( p, RR_LR, RR_LR_LEN);
00212       p += RR_LR_LEN;
00213    }
00214    if (tag && tag->len) {
00215       memcpy(p, RR_FROMTAG, RR_FROMTAG_LEN);
00216       p += RR_FROMTAG_LEN;
00217       memcpy(p, tag->s, tag->len);
00218       p += tag->len;
00219    }
00220    if (params && params->len) {
00221       memcpy(p, params->s, params->len);
00222       p += params->len;
00223    }
00224    
00225    memcpy(term, RR_TERM, RR_TERM_LEN);
00226    memcpy(r2, RR_R2, RR_R2_LEN);
00227 
00228    if (!(_l = insert_new_lump_after(_l, prefix, prefix_len, 0))) 
00229       goto lump_err;
00230    prefix = 0;
00231    _l = insert_subst_lump_after(_l, _inbound?SUBST_RCV_ALL:SUBST_SND_ALL, 0);
00232    if (_l ==0 )
00233       goto lump_err;
00234    if (enable_double_rr) {
00235       if (!(_l = insert_cond_lump_after(_l, COND_IF_DIFF_REALMS, 0)))
00236          goto lump_err;
00237       if (!(_l = insert_new_lump_after(_l, r2, RR_R2_LEN, 0)))
00238          goto lump_err;
00239       r2 = 0;
00240    } else {
00241       pkg_free(r2);
00242       r2 = 0;
00243    }
00244    _l2 = insert_new_lump_before(_l2, suffix, suffix_len, HDR_RECORDROUTE_T);
00245    if (_l2 == 0)
00246       goto lump_err;
00247    if (rr_param_buf.len) {
00248       _l2 = insert_rr_param_lump(_l2, rr_param_buf.s, rr_param_buf.len);
00249       if (_l2 == 0)
00250          goto lump_err;
00251    }
00252    suffix = 0;
00253    if (!(_l2 = insert_new_lump_before(_l2, term, RR_TERM_LEN, 0)))
00254       goto lump_err;
00255    term = 0;
00256    return 0;
00257    
00258 lump_err:
00259    LM_ERR("failed to insert lumps\n");
00260    if (prefix) pkg_free(prefix);
00261    if (suffix) pkg_free(suffix);
00262    if (r2) pkg_free(r2);
00263    if (term) pkg_free(term);
00264    return -4;
00265 }
00266 
00267 
00268 /*!
00269  * \brief Insert a new Record-Route header field with lr parameter
00270  *
00271  * Insert a new Record-Route header field and also 2nd one if it is enabled
00272  * and the realm changed so the 2nd record-route header will be necessary.
00273  * \param _m SIP message
00274  * \param params RR parameter
00275  * \return 0 on success, negative on failure
00276  */
00277 int record_route(struct sip_msg* _m, str *params)
00278 {
00279    struct lump* l, *l2;
00280    str user;
00281    struct to_body* from = NULL;
00282    str* tag;
00283    
00284    user.len = 0;
00285    
00286    if (add_username) {
00287       if (get_username(_m, &user) < 0) {
00288          LM_ERR("failed to extract username\n");
00289          return -1;
00290       }
00291    }
00292 
00293    if (append_fromtag) {
00294       if (parse_from_header(_m) < 0) {
00295          LM_ERR("From parsing failed\n");
00296          return -2;
00297       }
00298       from = (struct to_body*)_m->from->parsed;
00299       tag = &from->tag_value;
00300    } else {
00301       tag = 0;
00302    }
00303 
00304    if (rr_param_buf.len && rr_param_msg!=_m->id) {
00305       /* rr_params were set for a different message -> reset buffer */
00306       rr_param_buf.len = 0;
00307    }
00308 
00309    if (enable_double_rr) {
00310       l = anchor_lump(_m, _m->headers->name.s - _m->buf,0,HDR_RECORDROUTE_T);
00311       l2 = anchor_lump(_m, _m->headers->name.s - _m->buf, 0, 0);
00312       if (!l || !l2) {
00313          LM_ERR("failed to create an anchor\n");
00314          return -5;
00315       }
00316       l = insert_cond_lump_after(l, COND_IF_DIFF_REALMS, 0);
00317       l2 = insert_cond_lump_before(l2, COND_IF_DIFF_REALMS, 0);
00318       if (!l || !l2) {
00319          LM_ERR("failed to insert conditional lump\n");
00320          return -6;
00321       }
00322       if (build_rr(l, l2, &user, tag, params, OUTBOUND) < 0) {
00323          LM_ERR("failed to insert outbound Record-Route\n");
00324          return -7;
00325       }
00326    }
00327    
00328    l = anchor_lump(_m, _m->headers->name.s - _m->buf, 0, HDR_RECORDROUTE_T);
00329    l2 = anchor_lump(_m, _m->headers->name.s - _m->buf, 0, 0);
00330    if (!l || !l2) {
00331       LM_ERR("failed to create an anchor\n");
00332       return -3;
00333    }
00334    
00335    if (build_rr(l, l2, &user, tag, params, INBOUND) < 0) {
00336       LM_ERR("failed to insert inbound Record-Route\n");
00337       return -4;
00338    }
00339 
00340    /* reset the rr_param buffer */
00341    rr_param_buf.len = 0;
00342    return 0;
00343 }
00344 
00345 
00346 /*!
00347  * \brief Insert manually created Record-Route header
00348  *
00349  * Insert manually created Record-Route header, no checks, no restrictions,
00350  * always adds lr parameter, only fromtag is added automatically when requested.
00351  * Allocates new private memory for this.
00352  * \param _m SIP message
00353  * \param _data manually created RR header
00354  * \return 1 on success, negative on failure
00355  */
00356 int record_route_preset(struct sip_msg* _m, str* _data)
00357 {
00358    str user;
00359    struct to_body* from;
00360    struct lump* l;
00361    char* hdr, *p;
00362    int hdr_len;
00363 
00364    from = 0;
00365    user.len = 0;
00366    user.s = 0;
00367 
00368    if (add_username) {
00369       if (get_username(_m, &user) < 0) {
00370          LM_ERR("failed to extract username\n");
00371          return -1;
00372       }
00373    }
00374 
00375    if (append_fromtag) {
00376       if (parse_from_header(_m) < 0) {
00377          LM_ERR("From parsing failed\n");
00378          return -2;
00379       }
00380       from = (struct to_body*)_m->from->parsed;
00381    }
00382    
00383    l = anchor_lump(_m, _m->headers->name.s - _m->buf, 0, HDR_RECORDROUTE_T);
00384    if (!l) {
00385       LM_ERR("failed to create lump anchor\n");
00386       return -3;
00387    }
00388 
00389    hdr_len = RR_PREFIX_LEN;
00390    if (user.len)
00391       hdr_len += user.len + 1; /* @ */
00392    hdr_len += _data->len;
00393 
00394    if (append_fromtag && from->tag_value.len) {
00395       hdr_len += RR_FROMTAG_LEN + from->tag_value.len;
00396    }
00397    
00398    if (enable_full_lr) {
00399       hdr_len += RR_LR_FULL_LEN;
00400    } else {
00401       hdr_len += RR_LR_LEN;
00402    }
00403 
00404    hdr_len += RR_TERM_LEN;
00405 
00406    hdr = pkg_malloc(hdr_len);
00407    if (!hdr) {
00408       LM_ERR("no pkg memory left\n");
00409       return -4;
00410    }
00411 
00412    p = hdr;
00413    memcpy(p, RR_PREFIX, RR_PREFIX_LEN);
00414    p += RR_PREFIX_LEN;
00415 
00416    if (user.len) {
00417       memcpy(p, user.s, user.len);
00418       p += user.len;
00419       *p = '@';
00420       p++;
00421    }
00422 
00423    memcpy(p, _data->s, _data->len);
00424    p += _data->len;
00425    
00426    if (append_fromtag && from->tag_value.len) {
00427       memcpy(p, RR_FROMTAG, RR_FROMTAG_LEN);
00428       p += RR_FROMTAG_LEN;
00429       memcpy(p, from->tag_value.s, from->tag_value.len);
00430       p += from->tag_value.len;
00431    }
00432 
00433    if (enable_full_lr) {
00434       memcpy(p, RR_LR_FULL, RR_LR_FULL_LEN);
00435       p += RR_LR_FULL_LEN;
00436    } else {
00437       memcpy(p, RR_LR, RR_LR_LEN);
00438       p += RR_LR_LEN;
00439    }
00440 
00441    memcpy(p, RR_TERM, RR_TERM_LEN);
00442 
00443    if (!insert_new_lump_after(l, hdr, hdr_len, 0)) {
00444       LM_ERR("failed to insert new lump\n");
00445       pkg_free(hdr);
00446       return -5;
00447    }
00448    return 1;
00449 }
00450 
00451 
00452 /*!
00453  * \brief Get the RR parameter lump
00454  * \param root root of the lump list
00455  * \return pointer to the RR parameter lump, or NULL if not found
00456  */
00457 static struct lump *get_rr_param_lump( struct lump** root)
00458 {
00459    struct lump *r, *crt, *last;
00460    /* look on the "before" branch for the last added lump */
00461 
00462    last = 0;
00463    for( crt=*root ; crt && !last ; crt=crt->next,(*root)=crt ) {
00464       /* check on before list */
00465       for( r=crt->before ; r ; r=r->before ) {
00466          /* we are looking for the lump that adds the 
00467           * suffix of the RR header */
00468          if ( r->type==HDR_RECORDROUTE_T && r->op==LUMP_ADD)
00469             last = r;
00470       }
00471    }
00472    return last;
00473 }
00474 
00475 
00476 /*!
00477  * \brief Appends a new Record-Route parameter
00478  * \param msg SIP message
00479  * \param rr_param RR parameter
00480  * \return 0 on success, -1 on failure
00481  */
00482 int add_rr_param(struct sip_msg* msg, str* rr_param)
00483 {
00484    struct lump *last_param;
00485    struct lump *root;
00486 
00487    root = msg->add_rm;
00488    last_param = get_rr_param_lump( &root );
00489    if (last_param) {
00490       /* RR was already done -> have to add a new lump before this one */
00491       if (insert_rr_param_lump( last_param, rr_param->s, rr_param->len)==0) {
00492          LM_ERR("failed to add lump\n");
00493          goto error;
00494       }
00495       /* double routing enabled? */
00496       if (enable_double_rr) {
00497          if (root==0 || (last_param=get_rr_param_lump(&root))==0) {
00498             LM_CRIT("failed to locate double RR lump\n");
00499             goto error;
00500          }
00501          if (insert_rr_param_lump(last_param,rr_param->s,rr_param->len)==0){
00502             LM_ERR("failed to add 2nd lump\n");
00503             goto error;
00504          }
00505       }
00506    } else {
00507       /* RR not done yet -> store the param in the static buffer */
00508       if (rr_param_msg!=msg->id) {
00509          /* it's about a different message -> reset buffer */
00510          rr_param_buf.len = 0;
00511          rr_param_msg = msg->id;
00512       }
00513       if (rr_param_buf.len+rr_param->len>RR_PARAM_BUF_SIZE) {
00514          LM_ERR("maximum size of rr_param_buf exceeded\n");
00515          goto error;
00516       }
00517       memcpy( rr_param_buf.s+rr_param_buf.len, rr_param->s, rr_param->len);
00518       rr_param_buf.len += rr_param->len;
00519       LM_DBG("rr_param_buf=<%.*s>\n",rr_param_buf.len, rr_param_buf.s);
00520    }
00521    return 0;
00522 
00523 error:
00524    return -1;
00525 }

Generated on Thu May 24 10:00:29 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6