c68eb933bec0068de0dbec532442f81289ba6984
[sip-router] / modules_k / rr / record.c
1 /*
2  * $Id$
3  *
4  * Copyright (C) 2001-2003 FhG Fokus
5  *
6  * This file is part of Kamailio, a free SIP server.
7  *
8  * Kamailio is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version
12  *
13  * Kamailio is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License 
19  * along with this program; if not, write to the Free Software 
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 /*!
24  * \file
25  * \brief Route & Record-Route module, loose routing support
26  * \ingroup rr
27  */
28
29 /*!
30  * \defgroup rr RR :: Route & Record-Route Module
31  * This module contains record routing logic, as described in RFC 3261
32  * (see chapter 16.12 and 12.1.1 - UAS behavior).
33  */
34
35 #include <string.h>
36 #include "../../mem/mem.h"
37 #include "../../dprint.h"
38 #include "../../parser/parse_uri.h"
39 #include "../../parser/parse_from.h"
40 #include "../../str.h"
41 #include "../../data_lump.h"
42 #include "record.h"
43 #include "rr_mod.h"
44
45
46 #define RR_PREFIX "Record-Route: <sip:"
47 #define RR_PREFIX_LEN (sizeof(RR_PREFIX)-1)
48
49 #define RR_LR ";lr"
50 #define RR_LR_LEN (sizeof(RR_LR)-1)
51
52 #define RR_LR_FULL ";lr=on"
53 #define RR_LR_FULL_LEN (sizeof(RR_LR_FULL)-1)
54
55 #define RR_FROMTAG ";ftag="
56 #define RR_FROMTAG_LEN (sizeof(RR_FROMTAG)-1)
57
58 #define RR_R2 ";r2=on"
59 #define RR_R2_LEN (sizeof(RR_R2)-1)
60
61 #define RR_TERM ">"CRLF
62 #define RR_TERM_LEN (sizeof(RR_TERM)-1)
63
64 #define INBOUND  1      /*!< Insert inbound Record-Route */
65 #define OUTBOUND 0      /*!< Insert outbound Record-Route */
66
67 #define RR_PARAM_BUF_SIZE 512 /*!< buffer for RR parameter */
68
69
70 /*!
71  * \brief RR param buffer 
72  * \note used for storing RR param which are added before RR insertion
73  */
74 static char rr_param_buf_ptr[RR_PARAM_BUF_SIZE];
75 static str rr_param_buf = {rr_param_buf_ptr,0};
76 static unsigned int rr_param_msg;
77
78
79 /*!
80  * \brief Extract username from the Request URI
81  *
82  * Extract username from the Request URI. First try to look at the original
83  * Request URI and if there is no username use the new Request URI.
84  * \param _m SIP message
85  * \param _user username
86  * \return 0 on success, negative on errors
87  */
88 static inline int get_username(struct sip_msg* _m, str* _user)
89 {
90         struct sip_uri puri;
91
92              /* first try to look at r-uri for a username */
93         if (parse_uri(_m->first_line.u.request.uri.s, _m->first_line.u.request.uri.len, &puri) < 0) {
94                 LM_ERR("failed to parse R-URI\n");
95                 return -1;
96         }
97
98         /* no username in original uri -- hmm; maybe it is a uri
99          * with just host address and username is in a preloaded route,
100          * which is now no rewritten r-uri (assumed rewriteFromRoute
101          * was called somewhere in script's beginning) 
102          */
103         if (!puri.user.len && _m->new_uri.s) {
104                 if (parse_uri(_m->new_uri.s, _m->new_uri.len, &puri) < 0) {
105                         LM_ERR("failed to parse new_uri\n");
106                         return -2;
107                 }
108         }
109
110         _user->s = puri.user.s;
111         _user->len = puri.user.len;
112         return 0;
113 }
114
115
116 /*!
117  * \brief Insert RR parameter lump in new allocated private memory
118  * \param before lump list
119  * \param s parameter string
120  * \param l parameter string length
121  * \return pointer to new lump on success, NULL on failure
122  */
123 static inline struct lump *insert_rr_param_lump(struct lump *before,
124                                                 char *s, int l)
125 {
126         struct lump *rrp_l;
127         char *s1;
128
129         /* duplicate data in pkg mem */
130         s1 = (char*)pkg_malloc(l);
131         if (s1==0) {
132                 LM_ERR("no more pkg mem (%d)\n",l);
133                 return 0;
134         }
135         memcpy( s1, s, l);
136
137         /* add lump */
138         rrp_l = insert_new_lump_before( before, s1, l, HDR_RECORDROUTE_T);
139         if (rrp_l==0) {
140                 LM_ERR("failed to add before lump\n");
141                 pkg_free(s1);
142                 return 0;
143         }
144         return rrp_l;
145 }
146
147
148 /*!
149  * \brief Build a Record-Route header field
150  *
151 * Build a Record-Route header field, allocates new private memory for this.
152  * \param _l first lump
153  * \param _l2 second lump
154  * \param tag tag parameter
155  * \param params parameter
156  * \param _inbound inbound request
157  * \return 0 on success, negative on failure
158  */
159 static inline int build_rr(struct lump* _l, struct lump* _l2, str* user,
160                                                 str *tag, str *params, int _inbound)
161 {
162         char* prefix, *suffix, *term, *r2;
163         int suffix_len, prefix_len;
164         char *p;
165
166         prefix_len = RR_PREFIX_LEN + (user->len ? (user->len + 1) : 0);
167         if (enable_full_lr) {
168                 suffix_len = RR_LR_FULL_LEN + (params?params->len:0) +
169                                 ((tag && tag->len) ? (RR_FROMTAG_LEN + tag->len) : 0);
170         } else {
171                 suffix_len = RR_LR_LEN + (params?params->len:0) +
172                                 ((tag && tag->len) ? (RR_FROMTAG_LEN + tag->len) : 0);
173         }
174
175         prefix = pkg_malloc(prefix_len);
176         suffix = pkg_malloc(suffix_len);
177         term = pkg_malloc(RR_TERM_LEN);
178         r2 = pkg_malloc(RR_R2_LEN);
179
180         if (!prefix || !suffix || !term || !r2) {
181                 LM_ERR("No more pkg memory\n");
182                 if (suffix) pkg_free(suffix);
183                 if (prefix) pkg_free(prefix);
184                 if (term) pkg_free(term);
185                 if (r2) pkg_free(r2);
186                 return -3;
187         }
188         
189         memcpy(prefix, RR_PREFIX, RR_PREFIX_LEN);
190         if (user->len) {
191                 memcpy(prefix + RR_PREFIX_LEN, user->s, user->len);
192 #ifdef ENABLE_USER_CHECK
193                 /* don't add the ignored user into a RR */
194                 if(i_user.len && i_user.len == user->len && 
195                                 !strncmp(i_user.s, user->s, i_user.len))
196                 {
197                         if(prefix[RR_PREFIX_LEN]=='x')
198                                 prefix[RR_PREFIX_LEN]='y';
199                         else
200                                 prefix[RR_PREFIX_LEN]='x';
201                 }
202 #endif
203                 prefix[RR_PREFIX_LEN + user->len] = '@';
204         }
205
206         p = suffix;
207         if (enable_full_lr) {
208                 memcpy( p, RR_LR_FULL, RR_LR_FULL_LEN);
209                 p += RR_LR_FULL_LEN;
210         } else {
211                 memcpy( p, RR_LR, RR_LR_LEN);
212                 p += RR_LR_LEN;
213         }
214         if (tag && tag->len) {
215                 memcpy(p, RR_FROMTAG, RR_FROMTAG_LEN);
216                 p += RR_FROMTAG_LEN;
217                 memcpy(p, tag->s, tag->len);
218                 p += tag->len;
219         }
220         if (params && params->len) {
221                 memcpy(p, params->s, params->len);
222                 p += params->len;
223         }
224         
225         memcpy(term, RR_TERM, RR_TERM_LEN);
226         memcpy(r2, RR_R2, RR_R2_LEN);
227
228         if (!(_l = insert_new_lump_after(_l, prefix, prefix_len, 0))) 
229                 goto lump_err;
230         prefix = 0;
231         _l = insert_subst_lump_after(_l, _inbound?SUBST_RCV_ALL:SUBST_SND_ALL, 0);
232         if (_l ==0 )
233                 goto lump_err;
234         if (enable_double_rr) {
235                 if (!(_l = insert_cond_lump_after(_l, COND_IF_DIFF_REALMS, 0)))
236                         goto lump_err;
237                 if (!(_l = insert_new_lump_after(_l, r2, RR_R2_LEN, 0)))
238                         goto lump_err;
239                 r2 = 0;
240         } else {
241                 pkg_free(r2);
242                 r2 = 0;
243         }
244         _l2 = insert_new_lump_before(_l2, suffix, suffix_len, HDR_RECORDROUTE_T);
245         if (_l2 == 0)
246                 goto lump_err;
247         if (rr_param_buf.len) {
248                 _l2 = insert_rr_param_lump(_l2, rr_param_buf.s, rr_param_buf.len);
249                 if (_l2 == 0)
250                         goto lump_err;
251         }
252         suffix = 0;
253         if (!(_l2 = insert_new_lump_before(_l2, term, RR_TERM_LEN, 0)))
254                 goto lump_err;
255         term = 0;
256         return 0;
257         
258 lump_err:
259         LM_ERR("failed to insert lumps\n");
260         if (prefix) pkg_free(prefix);
261         if (suffix) pkg_free(suffix);
262         if (r2) pkg_free(r2);
263         if (term) pkg_free(term);
264         return -4;
265 }
266
267
268 /*!
269  * \brief Insert a new Record-Route header field with lr parameter
270  *
271  * Insert a new Record-Route header field and also 2nd one if it is enabled
272  * and the realm changed so the 2nd record-route header will be necessary.
273  * \param _m SIP message
274  * \param params RR parameter
275  * \return 0 on success, negative on failure
276  */
277 int record_route(struct sip_msg* _m, str *params)
278 {
279         struct lump* l, *l2;
280         str user;
281         struct to_body* from = NULL;
282         str* tag;
283         
284         user.len = 0;
285         
286         if (add_username) {
287                 if (get_username(_m, &user) < 0) {
288                         LM_ERR("failed to extract username\n");
289                         return -1;
290                 }
291         }
292
293         if (append_fromtag) {
294                 if (parse_from_header(_m) < 0) {
295                         LM_ERR("From parsing failed\n");
296                         return -2;
297                 }
298                 from = (struct to_body*)_m->from->parsed;
299                 tag = &from->tag_value;
300         } else {
301                 tag = 0;
302         }
303
304         if (rr_param_buf.len && rr_param_msg!=_m->id) {
305                 /* rr_params were set for a different message -> reset buffer */
306                 rr_param_buf.len = 0;
307         }
308
309         if (enable_double_rr) {
310                 l = anchor_lump(_m, _m->headers->name.s - _m->buf,0,HDR_RECORDROUTE_T);
311                 l2 = anchor_lump(_m, _m->headers->name.s - _m->buf, 0, 0);
312                 if (!l || !l2) {
313                         LM_ERR("failed to create an anchor\n");
314                         return -5;
315                 }
316                 l = insert_cond_lump_after(l, COND_IF_DIFF_REALMS, 0);
317                 l2 = insert_cond_lump_before(l2, COND_IF_DIFF_REALMS, 0);
318                 if (!l || !l2) {
319                         LM_ERR("failed to insert conditional lump\n");
320                         return -6;
321                 }
322                 if (build_rr(l, l2, &user, tag, params, OUTBOUND) < 0) {
323                         LM_ERR("failed to insert outbound Record-Route\n");
324                         return -7;
325                 }
326         }
327         
328         l = anchor_lump(_m, _m->headers->name.s - _m->buf, 0, HDR_RECORDROUTE_T);
329         l2 = anchor_lump(_m, _m->headers->name.s - _m->buf, 0, 0);
330         if (!l || !l2) {
331                 LM_ERR("failed to create an anchor\n");
332                 return -3;
333         }
334         
335         if (build_rr(l, l2, &user, tag, params, INBOUND) < 0) {
336                 LM_ERR("failed to insert inbound Record-Route\n");
337                 return -4;
338         }
339
340         /* reset the rr_param buffer */
341         rr_param_buf.len = 0;
342         return 0;
343 }
344
345
346 /*!
347  * \brief Insert manually created Record-Route header
348  *
349  * Insert manually created Record-Route header, no checks, no restrictions,
350  * always adds lr parameter, only fromtag is added automatically when requested.
351  * Allocates new private memory for this.
352  * \param _m SIP message
353  * \param _data manually created RR header
354  * \return 1 on success, negative on failure
355  */
356 int record_route_preset(struct sip_msg* _m, str* _data)
357 {
358         str user;
359         struct to_body* from;
360         struct lump* l;
361         char* hdr, *p;
362         int hdr_len;
363
364         from = 0;
365         user.len = 0;
366         user.s = 0;
367
368         if (add_username) {
369                 if (get_username(_m, &user) < 0) {
370                         LM_ERR("failed to extract username\n");
371                         return -1;
372                 }
373         }
374
375         if (append_fromtag) {
376                 if (parse_from_header(_m) < 0) {
377                         LM_ERR("From parsing failed\n");
378                         return -2;
379                 }
380                 from = (struct to_body*)_m->from->parsed;
381         }
382         
383         l = anchor_lump(_m, _m->headers->name.s - _m->buf, 0, HDR_RECORDROUTE_T);
384         if (!l) {
385                 LM_ERR("failed to create lump anchor\n");
386                 return -3;
387         }
388
389         hdr_len = RR_PREFIX_LEN;
390         if (user.len)
391                 hdr_len += user.len + 1; /* @ */
392         hdr_len += _data->len;
393
394         if (append_fromtag && from->tag_value.len) {
395                 hdr_len += RR_FROMTAG_LEN + from->tag_value.len;
396         }
397         
398         if (enable_full_lr) {
399                 hdr_len += RR_LR_FULL_LEN;
400         } else {
401                 hdr_len += RR_LR_LEN;
402         }
403
404         hdr_len += RR_TERM_LEN;
405
406         hdr = pkg_malloc(hdr_len);
407         if (!hdr) {
408                 LM_ERR("no pkg memory left\n");
409                 return -4;
410         }
411
412         p = hdr;
413         memcpy(p, RR_PREFIX, RR_PREFIX_LEN);
414         p += RR_PREFIX_LEN;
415
416         if (user.len) {
417                 memcpy(p, user.s, user.len);
418                 p += user.len;
419                 *p = '@';
420                 p++;
421         }
422
423         memcpy(p, _data->s, _data->len);
424         p += _data->len;
425         
426         if (append_fromtag && from->tag_value.len) {
427                 memcpy(p, RR_FROMTAG, RR_FROMTAG_LEN);
428                 p += RR_FROMTAG_LEN;
429                 memcpy(p, from->tag_value.s, from->tag_value.len);
430                 p += from->tag_value.len;
431         }
432
433         if (enable_full_lr) {
434                 memcpy(p, RR_LR_FULL, RR_LR_FULL_LEN);
435                 p += RR_LR_FULL_LEN;
436         } else {
437                 memcpy(p, RR_LR, RR_LR_LEN);
438                 p += RR_LR_LEN;
439         }
440
441         memcpy(p, RR_TERM, RR_TERM_LEN);
442
443         if (!insert_new_lump_after(l, hdr, hdr_len, 0)) {
444                 LM_ERR("failed to insert new lump\n");
445                 pkg_free(hdr);
446                 return -5;
447         }
448         return 1;
449 }
450
451
452 /*!
453  * \brief Get the RR parameter lump
454  * \param root root of the lump list
455  * \return pointer to the RR parameter lump, or NULL if not found
456  */
457 static struct lump *get_rr_param_lump( struct lump** root)
458 {
459         struct lump *r, *crt, *last;
460         /* look on the "before" branch for the last added lump */
461
462         last = 0;
463         for( crt=*root ; crt && !last ; crt=crt->next,(*root)=crt ) {
464                 /* check on before list */
465                 for( r=crt->before ; r ; r=r->before ) {
466                         /* we are looking for the lump that adds the 
467                          * suffix of the RR header */
468                         if ( r->type==HDR_RECORDROUTE_T && r->op==LUMP_ADD)
469                                 last = r;
470                 }
471         }
472         return last;
473 }
474
475
476 /*!
477  * \brief Appends a new Record-Route parameter
478  * \param msg SIP message
479  * \param rr_param RR parameter
480  * \return 0 on success, -1 on failure
481  */
482 int add_rr_param(struct sip_msg* msg, str* rr_param)
483 {
484         struct lump *last_param;
485         struct lump *root;
486
487         root = msg->add_rm;
488         last_param = get_rr_param_lump( &root );
489         if (last_param) {
490                 /* RR was already done -> have to add a new lump before this one */
491                 if (insert_rr_param_lump( last_param, rr_param->s, rr_param->len)==0) {
492                         LM_ERR("failed to add lump\n");
493                         goto error;
494                 }
495                 /* double routing enabled? */
496                 if (enable_double_rr) {
497                         if (root==0 || (last_param=get_rr_param_lump(&root))==0) {
498                                 LM_CRIT("failed to locate double RR lump\n");
499                                 goto error;
500                         }
501                         if (insert_rr_param_lump(last_param,rr_param->s,rr_param->len)==0){
502                                 LM_ERR("failed to add 2nd lump\n");
503                                 goto error;
504                         }
505                 }
506         } else {
507                 /* RR not done yet -> store the param in the static buffer */
508                 if (rr_param_msg!=msg->id) {
509                         /* it's about a different message -> reset buffer */
510                         rr_param_buf.len = 0;
511                         rr_param_msg = msg->id;
512                 }
513                 if (rr_param_buf.len+rr_param->len>RR_PARAM_BUF_SIZE) {
514                         LM_ERR("maximum size of rr_param_buf exceeded\n");
515                         goto error;
516                 }
517                 memcpy( rr_param_buf.s+rr_param_buf.len, rr_param->s, rr_param->len);
518                 rr_param_buf.len += rr_param->len;
519                 LM_DBG("rr_param_buf=<%.*s>\n",rr_param_buf.len, rr_param_buf.s);
520         }
521         return 0;
522
523 error:
524         return -1;
525 }