Revert "Revert "and added files""
[bcm963xx.git] / userapps / opensource / siproxd / src / proxy.c
1 /* -*- Mode: C; c-basic-offset: 3 -*-
2     Copyright (C) 2002-2005  Thomas Ries <tries@gmx.net>
3
4     This file is part of Siproxd.
5     
6     Siproxd is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10     
11     Siproxd is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15     
16     You should have received a copy of the GNU General Public License
17     along with Siproxd; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
19 */
20
21 #include "config.h"
22
23 #include <stdio.h>
24 #include <time.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/types.h>
28 #include <netinet/in.h>
29 #include <arpa/inet.h>
30 #include <netdb.h>
31
32 #include <osipparser2/osip_parser.h>
33 #include <osipparser2/sdp_message.h>
34
35 #include "siproxd.h"
36 #include "log.h"
37
38 static char const ident[]="$Id: proxy.c,v 1.80 2005/01/24 19:12:40 hb9xar Exp $";
39
40 /* configuration storage */
41 extern struct siproxd_config configuration;     /* defined in siproxd.c */
42
43 extern struct urlmap_s urlmap[];                /* URL mapping table     */
44 extern struct lcl_if_s local_addresses;
45
46
47 /*
48  * PROXY_REQUEST
49  *
50  * RETURNS
51  *      STS_SUCCESS on success
52  *      STS_FAILURE on error
53  *
54  * RFC3261
55  *    Section 16.3: Proxy Behavior - Request Validation
56  *    1. Reasonable Syntax
57  *    2. URI scheme
58  *    3. Max-Forwards
59  *    4. (Optional) Loop Detection
60  *    5. Proxy-Require
61  *    6. Proxy-Authorization
62  *
63  *    Section 16.6: Proxy Behavior - Request Forwarding
64  *    1.  Make a copy of the received request
65  *    2.  Update the Request-URI
66  *    3.  Update the Max-Forwards header field
67  *    4.  Optionally add a Record-route header field value
68  *    5.  Optionally add additional header fields
69  *    6.  Postprocess routing information
70  *    7.  Determine the next-hop address, port, and transport
71  *    8.  Add a Via header field value
72  *    9.  Add a Content-Length header field if necessary
73  *    10. Forward the new request
74  *    11. Set timer C
75  */
76 int proxy_request (sip_ticket_t *ticket) {
77    int i;
78    int sts;
79    int type;
80    struct in_addr sendto_addr;
81    osip_uri_t *url;
82    int port;
83    char *buffer;
84    osip_message_t *request;
85    struct sockaddr_in *from;
86    struct in_addr local_ip;
87
88    DEBUGC(DBCLASS_PROXY,"proxy_request");
89
90    if (ticket==NULL) {
91       ERROR("proxy_request: called with NULL ticket");
92       return STS_FAILURE;
93    }
94
95    request=ticket->sipmsg;
96    from=&ticket->from;
97
98    /*
99     * RFC 3261, Section 16.4
100     * Proxy Behavior - Route Information Preprocessing
101     * (process Route header)
102     */
103    route_preprocess(ticket);
104
105    /*
106     * figure out whether this is an incoming or outgoing request
107     * by doing a lookup in the registration table.
108     */
109 #define _OLD_DIRECTION_EVALUATION 0
110 #if _OLD_DIRECTION_EVALUATION
111    type = 0;
112    for (i=0; i<URLMAP_SIZE; i++) {
113       if (urlmap[i].active == 0) continue;
114
115       /* incoming request ('to' == 'masq') || (('to' == 'reg') && !REGISTER)*/
116       if ((compare_url(request->to->url, urlmap[i].masq_url)==STS_SUCCESS) ||
117           (!MSG_IS_REGISTER(request) &&
118            (compare_url(request->to->url, urlmap[i].reg_url)==STS_SUCCESS))) {
119          type=REQTYP_INCOMING;
120          DEBUGC(DBCLASS_PROXY,"incoming request from %s@%s from outbound",
121            request->from->url->username? request->from->url->username:"*NULL*",
122            request->from->url->host? request->from->url->host: "*NULL*");
123          break;
124       }
125
126       /* outgoing request ('from' == 'reg') */
127       if (compare_url(request->from->url, urlmap[i].reg_url)==STS_SUCCESS) {
128          type=REQTYP_OUTGOING;
129          DEBUGC(DBCLASS_PROXY,"outgoing request from %s@%s from inbound",
130            request->from->url->username? request->from->url->username:"*NULL*",
131            request->from->url->host? request->from->url->host: "*NULL*");
132          break;
133       }
134    }
135 #else
136    type = 0;
137    /*
138     * did I receive the telegram from a REGISTERED host?
139     * -> it must be an OUTGOING request
140     */
141    for (i=0; i<URLMAP_SIZE; i++) {
142       struct in_addr tmp_addr;
143
144       if (urlmap[i].active == 0) continue;
145       if (get_ip_by_host(urlmap[i].true_url->host, &tmp_addr) == STS_FAILURE) {
146          DEBUGC(DBCLASS_PROXY, "proxy_request: cannot resolve host [%s]",
147              urlmap[i].true_url);
148       } else {
149          DEBUGC(DBCLASS_PROXY, "proxy_request: reghost:%s ip:%s",
150                 urlmap[i].true_url->host, utils_inet_ntoa(from->sin_addr));
151          if (memcmp(&tmp_addr, &from->sin_addr, sizeof(tmp_addr)) == 0) {
152             type=REQTYP_OUTGOING;
153             break;
154          }
155       }
156    }
157
158    /*
159     * is the telegram directed to an internally registered host?
160     * -> it must be an INCOMING request
161     */
162    if (type == 0) {
163       for (i=0; i<URLMAP_SIZE; i++) {
164          if (urlmap[i].active == 0) continue;
165          /* RFC3261:
166           * 'To' contains a display name (Bob) and a SIP or SIPS URI
167           * (sip:bob@biloxi.com) towards which the request was originally
168           * directed.  Display names are described in RFC 2822 [3].
169           */
170
171          /* So this means, that we must check the SIP URI supplied with the
172           * INVITE method, as this points to the real wanted target.
173           * Q: does there exist a situation where the SIP URI itself does
174           *    point to "somewhere" but the To: points to the correct UA?
175           * So for now, we just look at both of them (SIP URI and To: header)
176           */
177
178          /* incoming request (SIP URI == 'masq') || ((SIP URI == 'reg') && !REGISTER)*/
179          if ((compare_url(request->req_uri, urlmap[i].masq_url)==STS_SUCCESS) ||
180              (!MSG_IS_REGISTER(request) &&
181               (compare_url(request->req_uri, urlmap[i].reg_url)==STS_SUCCESS))) {
182             type=REQTYP_INCOMING;
183             break;
184          }
185          /* incoming request ('to' == 'masq') || (('to' == 'reg') && !REGISTER)*/
186          if ((compare_url(request->to->url, urlmap[i].masq_url)==STS_SUCCESS) ||
187              (!MSG_IS_REGISTER(request) &&
188               (compare_url(request->to->url, urlmap[i].reg_url)==STS_SUCCESS))) {
189             type=REQTYP_INCOMING;
190             break;
191          }
192       }
193    }
194 #endif
195    ticket->direction=type;
196
197    /*
198     * logging of passing calls
199     */
200    if (configuration.log_calls) {
201       osip_uri_t *cont_url = NULL;
202       if (!osip_list_eol(request->contacts, 0))
203          cont_url = ((osip_contact_t*)(request->contacts->node->element))->url;
204       
205       /* INVITE */
206       if (MSG_IS_INVITE(request)) {
207          if (cont_url) {
208             INFO("%s Call from: %s@%s",
209                  (type==REQTYP_INCOMING) ? "Incoming":"Outgoing",
210                  cont_url->username ? cont_url->username:"*NULL*",
211                  cont_url->host ? cont_url->host : "*NULL*");
212          } else {
213             INFO("%s Call (w/o contact header) from: %s@%s",
214                  (type==REQTYP_INCOMING) ? "Incoming":"Outgoing",
215                  request->from->url->username ? 
216                     request->from->url->username:"*NULL*",
217                  request->from->url->host ? 
218                     request->from->url->host : "*NULL*");
219          }
220       /* BYE / CANCEL */
221       } else if (MSG_IS_BYE(request) || MSG_IS_CANCEL(request)) {
222          if (cont_url) {
223             INFO("Ending Call from: %s@%s",
224                  cont_url->username ? cont_url->username:"*NULL*",
225                  cont_url->host ? cont_url->host : "*NULL*");
226          } else {
227             INFO("Ending Call (w/o contact header) from: %s@%s",
228                  request->from->url->username ? 
229                     request->from->url->username:"*NULL*",
230                  request->from->url->host ? 
231                     request->from->url->host : "*NULL*");
232          }
233       }
234    } /* log_calls */
235
236
237    /*
238     * RFC 3261, Section 16.6 step 1
239     * Proxy Behavior - Request Forwarding - Make a copy
240     */
241    /* nothing to do here, copy is ready in 'request'*/
242
243    /* get destination address */
244    url=osip_message_get_uri(request);
245
246    /* Determine local address to use based on the To: address */
247    get_local_ip(request->to->url->host, &local_ip);
248    DEBUGC(DBCLASS_PROXY, "local IP: %s", inet_ntoa(local_ip));
249
250    switch (type) {
251   /*
252    * from an external host to the internal masqueraded host
253    */
254    case REQTYP_INCOMING:
255       DEBUGC(DBCLASS_PROXY,"incoming request from %s@%s from outbound",
256         request->from->url->username? request->from->url->username:"*NULL*",
257         request->from->url->host? request->from->url->host: "*NULL*");
258
259       /*
260        * RFC 3261, Section 16.6 step 2
261        * Proxy Behavior - Request Forwarding - Request-URI
262        * (rewrite request URI to point to the real host)
263        */
264       /* 'i' still holds the valid index into the URLMAP table */
265       if (check_rewrite_rq_uri(request) == STS_TRUE) {
266          proxy_rewrite_request_uri(request, i);
267       }
268
269       /* if this is CANCEL/BYE request, stop RTP proxying */
270       if (MSG_IS_BYE(request) || MSG_IS_CANCEL(request)) {
271          /* stop the RTP proxying stream(s) */
272          rtp_stop_fwd(osip_message_get_call_id(request), DIR_INCOMING);
273          rtp_stop_fwd(osip_message_get_call_id(request), DIR_OUTGOING);
274
275       /* check for incoming request */
276       } else if (MSG_IS_INVITE(request)) {
277          /* rewrite the body */
278          if (configuration.rtp_proxy_enable == 1) {
279             sts = proxy_rewrite_invitation_body(request, DIR_INCOMING, NULL);
280          }
281       } else if (MSG_IS_ACK(request)) {
282          /* rewrite the body */
283          sts = proxy_rewrite_invitation_body(request, DIR_INCOMING, NULL);
284       }
285       break;
286    
287   /*
288    * from the internal masqueraded host to an external host
289    */
290    case REQTYP_OUTGOING:
291       DEBUGC(DBCLASS_PROXY,"outgoing request from %s@%s from inbound",
292         request->from->url->username? request->from->url->username:"*NULL*",
293         request->from->url->host? request->from->url->host: "*NULL*");
294
295       /*
296        * RFC 3261, Section 16.6 step 2
297        * Proxy Behavior - Request Forwarding - Request-URI
298        */
299       /* nothing to do for an outgoing request */
300
301
302       /* if it is addressed to myself, then it must be some request
303        * method that I as a proxy do not support. Reject */
304 #if 0
305 /* careful - an internal UA might send an request to another internal UA.
306    This would be caught here, so don't do this. This situation should be
307    caught in the default part of the CASE statement below */
308       if (is_sipuri_local(ticket) == STS_TRUE) {
309          WARN("unsupported request [%s] directed to proxy from %s@%s -> %s@%s",
310             request->sip_method? request->sip_method:"*NULL*",
311             request->from->url->username? request->from->url->username:"*NULL*",
312             request->from->url->host? request->from->url->host : "*NULL*",
313             url->username? url->username : "*NULL*",
314             url->host? url->host : "*NULL*");
315
316          sip_gen_response(ticket, 403 /*forbidden*/);
317
318          return STS_FAILURE;
319       }
320 #endif
321
322       /* rewrite Contact header to represent the masqued address */
323       sip_rewrite_contact(ticket, DIR_OUTGOING, &local_ip);
324
325       /* if an INVITE, rewrite body */
326       if (MSG_IS_INVITE(request)) {
327          sts = proxy_rewrite_invitation_body(request, DIR_OUTGOING, &local_ip);
328       } else if (MSG_IS_ACK(request)) {
329          sts = proxy_rewrite_invitation_body(request, DIR_OUTGOING, &local_ip);
330       }
331
332       /* if this is CANCEL/BYE request, stop RTP proxying */
333       if (MSG_IS_BYE(request) || MSG_IS_CANCEL(request)) {
334          /* stop the RTP proxying stream(s) */
335          rtp_stop_fwd(osip_message_get_call_id(request), DIR_INCOMING);
336          rtp_stop_fwd(osip_message_get_call_id(request), DIR_OUTGOING);
337       }
338
339       break;
340    
341    default:
342       DEBUGC(DBCLASS_PROXY, "request [%s] from/to unregistered UA "
343            "(RQ: %s@%s -> %s@%s)",
344            request->sip_method? request->sip_method:"*NULL*",
345            request->from->url->username? request->from->url->username:"*NULL*",
346            request->from->url->host? request->from->url->host : "*NULL*",
347            url->username? url->username : "*NULL*",
348            url->host? url->host : "*NULL*");
349
350 /*
351  * we may end up here for two reasons:
352  *  1) An incomming request (from outbound) that is directed to
353  *     an unknown (not registered) local UA
354  *  2) an outgoing request from a local UA that is not registered.
355  *
356  * Case 1) we should probably answer with "404 Not Found",
357  * case 2) more likely a "403 Forbidden"
358  * 
359  * How about "408 Request Timeout" ?
360  *
361  */
362       sip_gen_response(ticket, 408 /* Request Timeout */);
363
364       return STS_FAILURE;
365    }
366
367
368    /*
369     * RFC 3261, Section 16.6 step 3
370     * Proxy Behavior - Request Forwarding - Max-Forwards
371     * (if Max-Forwards header exists, decrement by one, if it does not
372     * exist, add a new one with value SHOULD be 70)
373     */
374    {
375    osip_header_t *max_forwards;
376    int forwards_count = DEFAULT_MAXFWD;
377    char mfwd[8];
378
379    osip_message_get_max_forwards(request, 0, &max_forwards);
380    if (max_forwards == NULL) {
381       sprintf(mfwd, "%i", forwards_count);
382       osip_message_set_max_forwards(request, mfwd);
383    } else {
384       if (max_forwards->hvalue) {
385          forwards_count = atoi(max_forwards->hvalue);
386          forwards_count -=1;
387          osip_free (max_forwards->hvalue);
388       }
389
390       sprintf(mfwd, "%i", forwards_count);
391       max_forwards->hvalue = osip_strdup(mfwd);
392    }
393
394    DEBUGC(DBCLASS_PROXY,"setting Max-Forwards=%s",mfwd);
395    }
396
397    /*
398     * RFC 3261, Section 16.6 step 4
399     * Proxy Behavior - Request Forwarding - Add a Record-route header
400     */
401
402    /*
403     * for ALL incoming requests, include my Record-Route header.
404     * The local UA will probably send its answer to the topmost 
405     * Route Header (8.1.2 of RFC3261)
406     */
407    if (type == REQTYP_INCOMING) {
408       DEBUGC(DBCLASS_PROXY,"Adding my Record-Route");
409       route_add_recordroute(ticket);
410    } else {
411       /*
412        * outgoing packets must not have my record route header, as
413        * this likely will contain a private IP address (my inbound).
414        */
415       DEBUGC(DBCLASS_PROXY,"Purging Record-Routes (outgoing packet)");
416       route_purge_recordroute(ticket);
417    }
418
419    /*
420     * RFC 3261, Section 16.6 step 5
421     * Proxy Behavior - Request Forwarding - Add Additional Header Fields
422     */
423    /* NOT IMPLEMENTED (optional) */
424
425
426    /*
427     * RFC 3261, Section 16.6 step 6
428     * Proxy Behavior - Request Forwarding - Postprocess routing information
429     *
430     * If the copy contains a Route header field, the proxy MUST
431     * inspect the URI in its first value.  If that URI does not
432     * contain an lr parameter, the proxy MUST modify the copy as
433     * follows:
434     *
435     * -  The proxy MUST place the Request-URI into the Route header
436     *    field as the last value.
437     *
438     * -  The proxy MUST then place the first Route header field value
439     *    into the Request-URI and remove that value from the Route
440     *    header field.
441     */
442 #if 0
443    route_postprocess(ticket);
444 #endif
445
446    /*
447     * RFC 3261, Section 16.6 step 7
448     * Proxy Behavior - Determine Next-Hop Address
449     */
450 /*&&&& priority probably should be:
451  * 1) Route header
452  * 2) fixed outbound proxy
453  * 3) SIP URI
454  */
455    /*
456     * fixed or domain outbound proxy defined ?
457     */
458    if ((type == REQTYP_OUTGOING) &&
459        (sip_find_outbound_proxy(ticket, &sendto_addr, &port) == STS_SUCCESS)) {
460       DEBUGC(DBCLASS_PROXY, "proxy_request: have outbound proxy %s:%i",
461              utils_inet_ntoa(sendto_addr), port);
462    /*
463     * Route present?
464     * If so, fetch address from topmost Route: header and remove it.
465     */
466    } else if ((type == REQTYP_OUTGOING) && 
467               (request->routes && !osip_list_eol(request->routes, 0))) {
468       sts=route_determine_nexthop(ticket, &sendto_addr, &port);
469       if (sts == STS_FAILURE) {
470          DEBUGC(DBCLASS_PROXY, "proxy_request: route_determine_nexthop failed");
471          return STS_FAILURE;
472       }
473       DEBUGC(DBCLASS_PROXY, "proxy_request: have Route header to %s:%i",
474              utils_inet_ntoa(sendto_addr), port);
475    /*
476     * destination from SIP URI
477     */
478    } else {
479       /* get the destination from the SIP URI */
480       sts = get_ip_by_host(url->host, &sendto_addr);
481       if (sts == STS_FAILURE) {
482          DEBUGC(DBCLASS_PROXY, "proxy_request: cannot resolve URI [%s]",
483                 url->host);
484          return STS_FAILURE;
485       }
486
487       if (url->port) {
488          port=atoi(url->port);
489       } else {
490          port=SIP_PORT;
491       }
492       DEBUGC(DBCLASS_PROXY, "proxy_request: have SIP URI to %s:%i",
493              url->host, port);
494    }
495
496    /*
497     * RFC 3261, Section 16.6 step 8
498     * Proxy Behavior - Add a Via header field value
499     */
500    /* add my Via header line (outbound interface)*/
501    if (type == REQTYP_INCOMING) {
502       sts = sip_add_myvia(ticket, IF_INBOUND, NULL);
503       if (sts == STS_FAILURE) {
504          ERROR("adding my inbound via failed!");
505       }
506    } else {
507       sts = sip_add_myvia(ticket, IF_OUTBOUND, &local_ip);
508       if (sts == STS_FAILURE) {
509          ERROR("adding my outbound via failed!");
510          return STS_FAILURE;
511       }
512    }
513   /*
514    * RFC 3261, Section 16.6 step 9
515    * Proxy Behavior - Add a Content-Length header field if necessary
516    */
517   /* not necessary, already in message and we do not support TCP */
518
519   /*
520    * RFC 3261, Section 16.6 step 10
521    * Proxy Behavior - Forward the new request
522    */
523    sts = osip_message_to_str(request, &buffer);
524    if (sts != 0) {
525       ERROR("proxy_request: osip_message_to_str failed");
526       return STS_FAILURE;
527    }
528
529    sipsock_send(sendto_addr, port, ticket->protocol,
530                 buffer, strlen(buffer)); 
531    osip_free (buffer);
532
533   /*
534    * RFC 3261, Section 16.6 step 11
535    * Proxy Behavior - Set timer C
536    */
537   /* NOT IMPLEMENTED - does this really apply for stateless proxies? */
538
539    return STS_SUCCESS;
540 }
541
542
543 /*
544  * PROXY_RESPONSE
545  *
546  * RETURNS
547  *      STS_SUCCESS on success
548  *      STS_FAILURE on error
549  * RFC3261
550  *    Section 16.7: Proxy Behavior - Response Processing
551  *    1.  Find the appropriate response context
552  *    2.  Update timer C for provisional responses
553  *    3.  Remove the topmost Via
554  *    4.  Add the response to the response context
555  *    5.  Check to see if this response should be forwarded immediately
556  *    6.  When necessary, choose the best final response from the
557  *        response context
558  *    7.  Aggregate authorization header field values if necessary
559  *    8.  Optionally rewrite Record-Route header field values
560  *    9.  Forward the response
561  *    10. Generate any necessary CANCEL requests 
562  *
563  */
564 int proxy_response (sip_ticket_t *ticket) {
565    int i;
566    int sts;
567    int type;
568    struct in_addr sendto_addr, local_ip;
569    osip_via_t *via;
570    int port;
571    char *buffer;
572    osip_message_t *response;
573    struct sockaddr_in *from;
574
575    DEBUGC(DBCLASS_PROXY,"proxy_response");
576
577    if (ticket==NULL) {
578       ERROR("proxy_response: called with NULL ticket");
579       return STS_FAILURE;
580    }
581
582    response=ticket->sipmsg;
583    from=&ticket->from;
584
585    /* Determine local address to use based on the To: address */
586    get_local_ip(response->to->url->host, &local_ip);
587    DEBUGC(DBCLASS_PROXY, "local IP: %s", inet_ntoa(local_ip));
588
589    /*
590     * RFC 3261, Section 16.7 step 3
591     * Proxy Behavior - Response Processing - Remove my Via header field value
592     */
593    /* remove my Via header line */
594    sts = sip_del_myvia(ticket, &local_ip);
595    if (sts == STS_FAILURE) {
596       DEBUGC(DBCLASS_PROXY,"not addressed to my VIA, ignoring response");
597       return STS_FAILURE;
598    }
599
600    /*
601     * figure out if this is an request coming from the outside
602     * world to one of our registered clients
603     */
604
605    /* Ahhrghh...... a response seems to have NO contact information... 
606     * so let's take FROM instead...
607     * the TO and FROM headers are EQUAL to the request - that means 
608     * they are swapped in their meaning for a response...
609     */
610
611 #if _OLD_DIRECTION_EVALUATION
612    type = 0;
613    for (i=0; i<URLMAP_SIZE; i++) {
614       if (urlmap[i].active == 0) continue;
615
616       /* incoming response ('from' == 'masq') || ('from' == 'reg') */
617       if ((compare_url(response->from->url, urlmap[i].reg_url)==STS_SUCCESS) ||
618           (compare_url(response->from->url, urlmap[i].masq_url)==STS_SUCCESS)) {
619          type=RESTYP_INCOMING;
620          DEBUGC(DBCLASS_PROXY,"incoming response for %s@%s from outbound",
621            response->from->url->username? response->from->url->username:"*NULL*",
622            response->from->url->host? response->from->url->host : "*NULL*");
623          break;
624       }
625
626       /* outgoing response ('to' == 'reg') || ('to' == 'masq' ) */
627       if ((compare_url(response->to->url, urlmap[i].masq_url)==STS_SUCCESS) ||
628           (compare_url(response->to->url, urlmap[i].reg_url)==STS_SUCCESS)){
629          type=RESTYP_OUTGOING;
630          DEBUGC(DBCLASS_PROXY,"outgoing response for %s@%s from inbound",
631                 response->from->url->username ?
632                    response->from->url->username : "*NULL*",
633                 response->from->url->host ? 
634                    response->from->url->host : "*NULL*");
635          break;
636       }
637    }
638 #else
639    type = 0;
640    /*
641     * did I receive the telegram from a REGISTERED host?
642     * -> it must be an OUTGOING response
643     */
644    for (i=0; i<URLMAP_SIZE; i++) {
645       struct in_addr tmp_addr;
646       if (urlmap[i].active == 0) continue;
647
648       if (get_ip_by_host(urlmap[i].true_url->host, &tmp_addr) == STS_FAILURE) {
649          DEBUGC(DBCLASS_PROXY, "proxy_response: cannot resolve host [%s]",
650              urlmap[i].true_url);
651       } else {
652          DEBUGC(DBCLASS_PROXY, "proxy_response: reghost:%s ip:%s",
653                 urlmap[i].true_url->host, utils_inet_ntoa(from->sin_addr));
654          if (memcmp(&tmp_addr, &from->sin_addr, sizeof(tmp_addr)) == 0) {
655             type=RESTYP_OUTGOING;
656             break;
657          }
658       }
659    }
660    /*
661     * is the telegram directed to an internal registered host?
662     * -> it must be an INCOMING response
663     */
664    if (type == 0) {
665       for (i=0; i<URLMAP_SIZE; i++) {
666          if (urlmap[i].active == 0) continue;
667          /* incoming response ('from' == 'masq') || ('from' == 'reg') */
668          if ((compare_url(response->from->url, urlmap[i].reg_url)==STS_SUCCESS) ||
669              (compare_url(response->from->url, urlmap[i].masq_url)==STS_SUCCESS)) {
670             type=RESTYP_INCOMING;
671             break;
672          }
673       }
674    }
675 /* &&&& Open Issue &&&&
676    it has been seen with cross-provider calls that the FROM may be 'garbled'
677    (e.g 1393xxx@proxy01.sipphone.com for calls made sipphone -> FWD)
678    How can we deal with this? Should I take into consideration the 'Via'
679    headers? This is the only clue I have, pointing to the *real* UA.
680    Maybe I should put in a 'siproxd' ftag value to recognize it a header
681    put in by myself
682 */
683    if ((type == 0) && (!osip_list_eol(response->vias, 0))) {
684       osip_via_t *via;
685       struct in_addr addr_via, addr_myself;
686       int port_via, port_ua;
687
688       /* get the via address */
689       via = (osip_via_t *) osip_list_get (response->vias, 0);
690       DEBUGC(DBCLASS_PROXY, "proxy_response: check via [%s] for "
691              "registered UA",via->host);
692       sts=get_ip_by_host(via->host, &addr_via);
693       if (sts == STS_FAILURE) {
694          DEBUGC(DBCLASS_DNS, "proxy_response: cannot resolve VIA [%s]",
695                 via->host);
696       } else {
697
698          for (i=0; i<URLMAP_SIZE; i++) {
699             if (urlmap[i].active == 0) continue;
700             /* incoming response (1st via in list points to a registered UA) */
701             sts=get_ip_by_host(urlmap[i].true_url->host, &addr_myself);
702             if (sts == STS_FAILURE) {
703                DEBUGC(DBCLASS_DNS, "proxy_response: cannot resolve "
704                       "true_url [%s]", via->host);
705                continue;
706             }
707
708             port_via=0;
709             if (via->port) port_via=atoi(via->port);
710             if (port_via <= 0) port_via=SIP_PORT;
711
712             port_ua=0;
713             if (urlmap[i].true_url->port)
714                port_ua=atoi(urlmap[i].true_url->port);
715             if (port_ua <= 0) port_ua=SIP_PORT;
716
717             DEBUGC(DBCLASS_BABBLE, "proxy_response: checking for registered "
718                    "host [%s:%i] <-> [%s:%i]",
719                    urlmap[i].true_url->host, port_ua,
720                    via->host, port_via);
721
722             if ((memcmp(&addr_myself, &addr_via, sizeof(addr_myself))==0) &&
723                 (port_via == port_ua)) {
724                type=RESTYP_INCOMING;
725                break;
726             }
727          }
728       }
729    }
730     
731 #endif
732    ticket->direction=type;
733
734 /*
735  * ok, we got a response that we are allowed to process.
736  */
737    switch (type) {
738   /*
739    * from an external host to the internal masqueraded host
740    */
741    case RESTYP_INCOMING:
742       DEBUGC(DBCLASS_PROXY,"incoming response for %s@%s from outbound",
743         response->from->url->username? response->from->url->username:"*NULL*",
744         response->from->url->host? response->from->url->host : "*NULL*");
745
746       /*
747        * Response for INVITE - deal with RTP data in body and
748        *                       start RTP proxy stream(s). In case
749        *                       of a negative answer, stop RTP stream
750        */
751       if (MSG_IS_RESPONSE_FOR(response,"INVITE")) {
752          /* positive response, start RTP stream */
753          if ((MSG_IS_STATUS_1XX(response)) || 
754               (MSG_IS_STATUS_2XX(response))) {
755             if (configuration.rtp_proxy_enable == 1) {
756                DEBUGC(DBCLASS_PROXY,"here");
757                sts = proxy_rewrite_invitation_body(response, DIR_INCOMING, NULL);
758             }
759          /* negative - stop a possibly started RTP stream */
760          } else if ((MSG_IS_STATUS_4XX(response))  ||
761                      (MSG_IS_STATUS_5XX(response)) ||
762                      (MSG_IS_STATUS_6XX(response))) {
763             rtp_stop_fwd(osip_message_get_call_id(response), DIR_INCOMING);
764             rtp_stop_fwd(osip_message_get_call_id(response), DIR_OUTGOING);
765          }
766       } /* if INVITE */
767
768       /*
769        * Response for REGISTER - special handling of Contact header
770        */
771       if (MSG_IS_RESPONSE_FOR(response,"REGISTER")) {
772          /*
773           * REGISTER returns *my* Contact header information.
774           * Rewrite Contact header back to represent the true address.
775           * Other responses do return the Contact header of the sender.
776           */
777          sip_rewrite_contact(ticket, DIR_INCOMING, NULL);
778       }
779
780       /* 
781        * Response for SUBSCRIBE
782        *
783        * HACK for Grandstream SIP phones (with newer firmware like 1.0.4.40):
784        *   They send a SUBSCRIBE request to the registration server. In
785        *   case of beeing registering directly to siproxd, this request of
786        *   course will eventually be forwarded back to the same UA.
787        *   Grandstream then does reply with an '202' response (A 202
788        *   response merely indicates that the subscription has been
789        *   understood, and that authorization may or may not have been
790        *   granted), which then of course is forwarded back to the phone.
791        *   Ans it seems that the Grandstream can *not* *handle* this
792        *   response, as it immediately sends another SUBSCRIBE request.
793        *   And this games goes on and on and on...
794        *
795        *   As a workaround we will transform any 202 response to a
796        *   '404 unknown destination'
797        *   
798        */
799 {
800       osip_header_t *ua_hdr=NULL;
801       osip_message_get_user_agent(response, 0, &ua_hdr);
802       if (ua_hdr && ua_hdr->hvalue &&
803           (osip_strncasecmp(ua_hdr->hvalue,"grandstream", 11)==0) &&
804           (MSG_IS_RESPONSE_FOR(response,"SUBSCRIBE")) &&
805           (MSG_TEST_CODE(response, 202))) {
806          DEBUGC(DBCLASS_PROXY, "proxy_response: Grandstream hack 202->404");
807          response->status_code=404;
808       }
809 }
810       break;
811    
812   /*
813    * from the internal masqueraded host to an external host
814    */
815    case RESTYP_OUTGOING:
816       DEBUGC(DBCLASS_PROXY,"outgoing response for %s@%s from inbound",
817              response->from->url->username ?
818                 response->from->url->username : "*NULL*",
819              response->from->url->host ? 
820                 response->from->url->host : "*NULL*");
821
822       /* rewrite Contact header to represent the masqued address */
823       sip_rewrite_contact(ticket, DIR_OUTGOING, NULL);
824
825       /*
826        * If an 2xx OK or 1xx response, answer to an INVITE request,
827        * rewrite body
828        *
829        * In case of a negative answer, stop RTP stream
830        */
831       if (MSG_IS_RESPONSE_FOR(response,"INVITE")) {
832          /* positive response, start RTP stream */
833          if ((MSG_IS_STATUS_1XX(response)) || 
834               (MSG_IS_STATUS_2XX(response))) {
835             /* This is an outgoing response, therefore an outgoing stream */
836             sts = proxy_rewrite_invitation_body(response, DIR_OUTGOING, NULL);
837          /* megative - stop a possibly started RTP stream */
838          } else if ((MSG_IS_STATUS_4XX(response))  ||
839                      (MSG_IS_STATUS_5XX(response)) ||
840                      (MSG_IS_STATUS_6XX(response))) {
841             rtp_stop_fwd(osip_message_get_call_id(response), DIR_INCOMING);
842             rtp_stop_fwd(osip_message_get_call_id(response), DIR_OUTGOING);
843          }
844       } /* if INVITE */
845
846       break;
847    
848    default:
849       DEBUGC(DBCLASS_PROXY, "response from/to unregistered UA (%s@%s)",
850            response->from->url->username? response->from->url->username:"*NULL*",
851            response->from->url->host? response->from->url->host : "*NULL*");
852       return STS_FAILURE;
853    }
854
855    /*
856     * for ALL incoming response include my Record-Route header.
857     * The local UA will probably send its answer to the topmost 
858     * Route Header (8.1.2 of RFC3261)
859     */
860     if (type == RESTYP_INCOMING) {
861        DEBUGC(DBCLASS_PROXY,"Adding my Record-Route");
862        route_add_recordroute(ticket);
863     } else {
864        /*
865         * outgoing packets must not have my record route header, as
866         * this likely will contain a private IP address (my inbound).
867         */
868        DEBUGC(DBCLASS_PROXY,"Purging Record-Routes (outgoing packet)");
869        route_purge_recordroute(ticket);
870     }
871
872    /*
873     * Determine Next-Hop Address
874     */
875 /*&&&& priority probably should be:
876  * 1) Route header
877  * 2) fixed outbound proxy
878  * 3) SIP URI
879  */
880    /*
881     * check if we need to send to an outbound proxy
882     */
883    if ((type == RESTYP_OUTGOING) &&
884        (sip_find_outbound_proxy(ticket, &sendto_addr, &port) == STS_SUCCESS)) {
885       DEBUGC(DBCLASS_PROXY, "proxy_response: have outbound proxy %s:%i",
886              utils_inet_ntoa(sendto_addr), port);
887    /*
888     * Route present?
889     * If so, fetch address from topmost Route: header and remove it.
890     */
891    } else if ((type == RESTYP_OUTGOING) && 
892               (response->routes && !osip_list_eol(response->routes, 0))) {
893       sts=route_determine_nexthop(ticket, &sendto_addr, &port);
894       if (sts == STS_FAILURE) {
895          DEBUGC(DBCLASS_PROXY, "proxy_response: route_determine_nexthop failed");
896          return STS_FAILURE;
897       }
898       DEBUGC(DBCLASS_PROXY, "proxy_response: have Route header to %s:%i",
899              utils_inet_ntoa(sendto_addr), port);
900    } else {
901       /* get target address and port from VIA header */
902       via = (osip_via_t *) osip_list_get (response->vias, 0);
903       if (via == NULL) {
904          ERROR("proxy_response: list_get via failed");
905          return STS_FAILURE;
906       }
907
908       sts = get_ip_by_host(via->host, &sendto_addr);
909       if (sts == STS_FAILURE) {
910          DEBUGC(DBCLASS_PROXY, "proxy_response: cannot resolve VIA [%s]",
911                 via->host);
912          return STS_FAILURE;
913       }
914
915       if (via->port) {
916          port=atoi(via->port);
917       } else {
918          port=SIP_PORT;
919       }
920    }
921
922    sts = osip_message_to_str(response, &buffer);
923    if (sts != 0) {
924       ERROR("proxy_response: osip_message_to_str failed");
925       return STS_FAILURE;
926    }
927
928    sipsock_send(sendto_addr, port, ticket->protocol,
929                 buffer, strlen(buffer)); 
930    osip_free (buffer);
931    return STS_SUCCESS;
932 }
933
934
935 /*
936  * PROXY_REWRITE_INVITATION_BODY
937  *
938  * rewrites the outgoing INVITATION request or response packet
939  * 
940  * RETURNS
941  *      STS_SUCCESS on success
942  *      STS_FAILURE on error
943  */
944 int proxy_rewrite_invitation_body(osip_message_t *mymsg, int direction,
945                                   struct in_addr *local_ip){
946    osip_body_t *body;
947    sdp_message_t  *sdp;
948    struct in_addr map_addr, addr_sess, addr_media, outside_addr, inside_addr;
949    int sts;
950    char *bodybuff;
951    char clen[8]; /* content length: probably never more than 7 digits !*/
952    int map_port, msg_port;
953    int media_stream_no;
954    sdp_connection_t *sdp_conn;
955    sdp_media_t *sdp_med;
956    int rtp_direction=0;
957    int have_c_media=0;
958
959    if (configuration.rtp_proxy_enable == 0) return STS_SUCCESS;
960
961    /*
962     * get SDP structure
963     */
964    sts = osip_message_get_body(mymsg, 0, &body);
965    if (sts != 0) {
966       if ((MSG_IS_RESPONSE_FOR(mymsg,"INVITE")) &&
967           (MSG_IS_STATUS_1XX(mymsg))) {
968          /* 1xx responses *MAY* contain SDP data */
969          DEBUGC(DBCLASS_PROXY, "rewrite_invitation_body: "
970                 "no body found in message");
971          return STS_SUCCESS;
972       } else {
973          /* INVITE request and 200 response *MUST* contain SDP data */
974          ERROR("rewrite_invitation_body: no body found in message");
975          return STS_FAILURE;
976       }
977    }
978
979    sts = osip_body_to_str(body, &bodybuff);
980    if (sts != 0) {
981       ERROR("rewrite_invitation_body: unable to sip_body_to_str");
982    }
983    sts = sdp_message_init(&sdp);
984    sts = sdp_message_parse (sdp, bodybuff);
985    osip_free(bodybuff);
986    if (sts != 0) {
987       ERROR("rewrite_invitation_body: unable to sdp_message_parse body");
988       sdp_message_free(sdp);
989       return STS_FAILURE;
990    }
991
992
993 if (configuration.debuglevel)
994 { /* just dump the buffer */
995    char *tmp, *tmp2;
996    sts = osip_message_get_body(mymsg, 0, &body);
997    sts = osip_body_to_str(body, &tmp);
998    osip_content_length_to_str(mymsg->content_length, &tmp2);
999    DEBUG("Body before rewrite (clen=%s, strlen=%i):\n%s\n----",
1000          tmp2, strlen(tmp), tmp);
1001    osip_free(tmp);
1002    osip_free(tmp2);
1003 }
1004
1005    /*
1006     * RTP proxy: get ready and start forwarding
1007     * start forwarding for each media stream ('m=' item in SIP message)
1008     */
1009
1010    /* get outbound address */
1011    if (get_ip_by_ifname(configuration.outbound_if, &outside_addr) != 
1012        STS_SUCCESS) {
1013       ERROR("can't find outbound interface %s - configuration error?",
1014             configuration.outbound_if);
1015       sdp_message_free(sdp);
1016       return STS_FAILURE;
1017    }
1018
1019    if (local_ip == NULL) {
1020       /* get inbound address */
1021       if (get_ip_by_ifname(configuration.inbound_if, &inside_addr) !=
1022           STS_SUCCESS) {
1023          ERROR("can't find inbound interface %s - configuration error?",
1024                configuration.inbound_if);
1025          sdp_message_free(sdp);
1026          return STS_FAILURE;
1027       }
1028    } else {
1029       outside_addr = *local_ip;
1030    }
1031
1032    /* figure out what address to use for RTP masquerading */
1033    if (MSG_IS_REQUEST(mymsg)) {
1034       if (direction == DIR_INCOMING) {
1035          memcpy(&map_addr, &inside_addr, sizeof (map_addr));
1036          rtp_direction = DIR_OUTGOING;
1037       } else {
1038          memcpy(&map_addr, &outside_addr, sizeof (map_addr));
1039          rtp_direction = DIR_INCOMING;
1040       }
1041    } else /* MSG_IS_REPONSE(mymsg) */ {
1042       if (direction == DIR_INCOMING) {
1043          memcpy(&map_addr, &inside_addr, sizeof (map_addr));
1044          rtp_direction = DIR_OUTGOING;
1045       } else {
1046          memcpy(&map_addr, &outside_addr, sizeof (map_addr));
1047          rtp_direction = DIR_INCOMING;
1048       }
1049    }
1050
1051    DEBUGC(DBCLASS_PROXY, "proxy_rewrite_invitation_body: SIP[%s %s] RTP[%s %s]",
1052           MSG_IS_REQUEST(mymsg)? "RQ" : "RS",
1053           (direction==DIR_INCOMING)? "IN" : "OUT",
1054           (rtp_direction==DIR_INCOMING)? "IN" : "OUT",
1055           utils_inet_ntoa(map_addr));
1056
1057
1058    /*
1059     * first, check presence of a 'c=' item on session level
1060     */
1061    if (sdp->c_connection==NULL || sdp->c_connection->c_addr==NULL) {
1062       /*
1063        * No 'c=' on session level, search on media level now
1064        *
1065        * According to RFC2327, ALL media description must
1066        * include a 'c=' item now:
1067        */
1068       media_stream_no=0;
1069       while (!sdp_message_endof_media(sdp, media_stream_no)) {
1070          /* check if n'th media stream is present */
1071          if (sdp_message_c_addr_get(sdp, media_stream_no, 0) == NULL) {
1072             ERROR("SDP: have no 'c=' on session level and neither "
1073                   "on media level (media=%i)",media_stream_no);
1074             sdp_message_free(sdp);
1075             return STS_FAILURE;
1076          }
1077          media_stream_no++;
1078       } /* while */
1079    }
1080
1081    /* Required 'c=' items ARE present */
1082
1083
1084    /*
1085     * rewrite 'c=' item on session level if present and not yet done.
1086     * remember the original address in addr_sess
1087     */
1088    memset(&addr_sess, 0, sizeof(addr_sess));
1089    if (sdp->c_connection && sdp->c_connection->c_addr) {
1090       sts = get_ip_by_host(sdp->c_connection->c_addr, &addr_sess);
1091       if (sts == STS_FAILURE) {
1092          ERROR("SDP: cannot resolve session 'c=' host [%s]",
1093                sdp->c_connection->c_addr);
1094          sdp_message_free(sdp);
1095          return STS_FAILURE;
1096       }
1097       /*
1098        * Rewrite
1099        * an IP address of 0.0.0.0 means *MUTE*, don't rewrite such
1100        */
1101       /*&&&& should use gethostbyname here */
1102       if (strcmp(sdp->c_connection->c_addr, "0.0.0.0") != 0) {
1103          osip_free(sdp->c_connection->c_addr);
1104          sdp->c_connection->c_addr=osip_malloc(HOSTNAME_SIZE);
1105          sprintf(sdp->c_connection->c_addr, "%s", utils_inet_ntoa(map_addr));
1106       } else {
1107          /* 0.0.0.0 - don't rewrite */
1108          DEBUGC(DBCLASS_PROXY, "proxy_rewrite_invitation_body: "
1109                 "got a MUTE c= record (on session level - legal?)");
1110       }
1111    }
1112
1113
1114    /*
1115     * rewrite 'o=' item (originator) on session level if present.
1116     */
1117    if (sdp->o_addrtype && sdp->o_addr) {
1118       if (strcmp(sdp->o_addrtype, "IP4") != 0) {
1119          ERROR("got IP6 in SDP originator - not yet suported by siproxd");
1120          sdp_message_free(sdp);
1121          return STS_FAILURE;
1122       }
1123
1124       osip_free(sdp->o_addr);
1125       sdp->o_addr=osip_malloc(HOSTNAME_SIZE);
1126       sprintf(sdp->o_addr, "%s", utils_inet_ntoa(map_addr));
1127    }
1128
1129
1130    /*
1131     * loop through all media descritions,
1132     * start RTP proxy and rewrite them
1133     */
1134    for (media_stream_no=0;;media_stream_no++) {
1135       /* check if n'th media stream is present */
1136       if (sdp_message_m_port_get(sdp, media_stream_no) == NULL) break;
1137
1138       /*
1139        * check if a 'c=' item is present in this media description,
1140        * if so -> rewrite it
1141        */
1142       memset(&addr_media, 0, sizeof(addr_media));
1143       have_c_media=0;
1144       sdp_conn=sdp_message_connection_get(sdp, media_stream_no, 0);
1145       if (sdp_conn && sdp_conn->c_addr) {
1146          /*&&&& should use gethostbyname here as well */
1147          if (strcmp(sdp_conn->c_addr, "0.0.0.0") != 0) {
1148             sts = get_ip_by_host(sdp_conn->c_addr, &addr_media);
1149             have_c_media=1;
1150             /* have a valid address */
1151             osip_free(sdp_conn->c_addr);
1152             sdp_conn->c_addr=osip_malloc(HOSTNAME_SIZE);
1153             sprintf(sdp_conn->c_addr, "%s", utils_inet_ntoa(map_addr));
1154          } else {
1155             /* 0.0.0.0 - don't rewrite */
1156             DEBUGC(DBCLASS_PROXY, "proxy_rewrite_invitation_body: got a "
1157                    "MUTE c= record (media level)");
1158          }
1159       }
1160
1161       /* start an RTP proxying stream */
1162       if (sdp_message_m_port_get(sdp, media_stream_no)) {
1163          msg_port=atoi(sdp_message_m_port_get(sdp, media_stream_no));
1164
1165          if (msg_port > 0) {
1166             osip_uri_t *cont_url = NULL;
1167             char *client_id=NULL;
1168             /* try to get some additional UA specific unique ID.
1169              * Try:
1170              * 1) User part of Contact header
1171              * 2) Host part of Contact header (will be different
1172              *    between internal UA and external UA)
1173              */
1174             if (!osip_list_eol(mymsg->contacts, 0))
1175                cont_url = ((osip_contact_t*)(mymsg->contacts->node->element))->url;
1176             if (cont_url) {
1177                client_id=cont_url->username;
1178                if (client_id == NULL) client_id=cont_url->host;
1179             }
1180
1181
1182             /*
1183              * do we have a 'c=' item on media level?
1184              * if not, use the same as on session level
1185              */
1186             if (have_c_media == 0) {
1187                memcpy(&addr_media, &addr_sess, sizeof(addr_sess));
1188             }
1189
1190             sts = rtp_start_fwd(osip_message_get_call_id(mymsg),
1191                                 client_id,
1192                                 rtp_direction,
1193                                 media_stream_no,
1194                                 map_addr, &map_port,
1195                                 addr_media, msg_port);
1196
1197             if (sts == STS_SUCCESS) {
1198                /* and rewrite the port */
1199                sdp_med=osip_list_get(sdp->m_medias, media_stream_no);
1200                if (sdp_med && sdp_med->m_port) {
1201                   osip_free(sdp_med->m_port);
1202                   sdp_med->m_port=osip_malloc(8); /* 5 digits, \0 + align */
1203                   sprintf(sdp_med->m_port, "%i", map_port);
1204                   DEBUGC(DBCLASS_PROXY, "proxy_rewrite_invitation_body: "
1205                          "m= rewrote port to [%i]",map_port);
1206                } else {
1207                   ERROR("rewriting port in m= failed sdp_med=%p, "
1208                         "m_number_of_port=%p", sdp_med, sdp_med->m_port);
1209                }
1210             } /* sts == success */
1211          } /* if msg_port > 0 */
1212       } else {
1213          /* no port defined - skip entry */
1214          WARN("no port defined in m=(media) stream_no=%i", media_stream_no);
1215          continue;
1216       }
1217    } /* for media_stream_no */
1218
1219    /* remove old body */
1220    sts = osip_list_remove(mymsg->bodies, 0);
1221    osip_body_free(body);
1222
1223    /* dump new body */
1224    sdp_message_to_str(sdp, &bodybuff);
1225
1226    /* free sdp structure */
1227    sdp_message_free(sdp);
1228
1229    /* include new body */
1230    osip_message_set_body(mymsg, bodybuff);
1231
1232    /* free content length resource and include new one*/
1233    osip_content_length_free(mymsg->content_length);
1234    mymsg->content_length=NULL;
1235    sprintf(clen,"%i",strlen(bodybuff));
1236    sts = osip_message_set_content_length(mymsg, clen);
1237
1238    /* free old body */
1239    osip_free(bodybuff);
1240
1241 if (configuration.debuglevel)
1242 { /* just dump the buffer */
1243    char *tmp, *tmp2;
1244    sts = osip_message_get_body(mymsg, 0, &body);
1245    sts = osip_body_to_str(body, &tmp);
1246    osip_content_length_to_str(mymsg->content_length, &tmp2);
1247    DEBUG("Body after rewrite (clen=%s, strlen=%i):\n%s\n----",
1248          tmp2, strlen(tmp), tmp);
1249    osip_free(tmp);
1250    osip_free(tmp2);
1251 }
1252    return STS_SUCCESS;
1253 }
1254
1255
1256 /*
1257  * PROXY_REWRITE_REQUEST_URI
1258  *
1259  * rewrites the incoming Request URI
1260  * 
1261  * RETURNS
1262  *      STS_SUCCESS on success
1263  */
1264 int proxy_rewrite_request_uri(osip_message_t *mymsg, int idx){
1265    char *host;
1266    char *port;
1267    osip_uri_t *url;
1268
1269    if ((idx >= URLMAP_SIZE) || (idx < 0)) {
1270       WARN("proxy_rewrite_request_uri: called with invalid index");
1271       return STS_FAILURE;
1272    }
1273
1274    DEBUGC(DBCLASS_PROXY,"rewriting incoming Request URI");
1275    url=osip_message_get_uri(mymsg);
1276
1277    /* set the true host */
1278    if (url->host) osip_free(url->host);url->host=NULL;
1279    if (urlmap[idx].true_url->host) {
1280       DEBUGC(DBCLASS_BABBLE,"proxy_rewrite_request_uri: host=%s",
1281              urlmap[idx].true_url->host);
1282       host = (char *)malloc(strlen(urlmap[idx].true_url->host)+1);
1283       memcpy(host, urlmap[idx].true_url->host, strlen(urlmap[idx].true_url->host));
1284       host[strlen(urlmap[idx].true_url->host)]='\0';
1285       osip_uri_set_host(url, host);
1286    }
1287
1288    /* set the true port */
1289    if (url->port) osip_free(url->port);url->port=NULL;
1290    if (urlmap[idx].true_url->port) {
1291       DEBUGC(DBCLASS_BABBLE,"proxy_rewrite_request_uri: port=%s",
1292              urlmap[idx].true_url->port);
1293       port = (char *)malloc(strlen(urlmap[idx].true_url->port)+1);
1294       memcpy(port, urlmap[idx].true_url->port, strlen(urlmap[idx].true_url->port));
1295       port[strlen(urlmap[idx].true_url->port)]='\0';
1296       osip_uri_set_port(url, port);
1297    }
1298    return STS_SUCCESS;
1299 }