http://downloads.netgear.com/files/GPL/GPL_Source_V361j_DM111PSP_series_consumer_rele...
[bcm963xx.git] / userapps / opensource / siproxd / src / route_processing.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: route_processing.c,v 1.1.1.1 2006/05/18 10:47:25 michaelc Exp $";
39
40 /* configuration storage */
41 extern struct siproxd_config configuration;     /* defined in siproxd.c */
42
43
44 /*
45  * PROXY_PREPROCESS_ROUTE
46  *
47  * Route Information Preprocessing
48  * 
49  * RETURNS
50  *      STS_SUCCESS on success
51  */
52 int route_preprocess(sip_ticket_t *ticket){
53    osip_message_t *mymsg=ticket->sipmsg;
54    int sts;
55    osip_uri_t *url;
56    int dest_port;
57    int last;
58    struct in_addr addr1, addr2, addr3;
59    osip_route_t *route;
60    osip_uri_param_t *param=NULL;
61
62    if ((mymsg->routes==NULL) || (osip_list_size(mymsg->routes)<=0)) {
63       DEBUGC(DBCLASS_PROXY, "route_preprocess: no Route header present");
64       return STS_SUCCESS;
65    }
66
67    if (get_ip_by_ifname(configuration.inbound_if, &addr2) != STS_SUCCESS) {
68       ERROR("can't find inbound interface %s - configuration error?",
69             configuration.inbound_if);
70       return STS_FAILURE;
71    }
72    if (get_ip_by_ifname(configuration.outbound_if, &addr3)!= STS_SUCCESS) {
73       ERROR("can't find outbound interface %s - configuration error?",
74             configuration.outbound_if);
75       return STS_FAILURE;
76    }
77
78    /*
79     * 16.4 Route Information Preprocessing:
80     * The proxy MUST inspect the Request-URI of the request.  If the
81     * Request-URI of the request contains a value this proxy previously
82     * placed into a Record-Route header field (see Section 16.6 item 4),
83     * the proxy MUST replace the Request-URI in the request with the last
84     * value from the Route header field, and remove that value from the
85     * Route header field.  The proxy MUST then proceed as if it received
86     * this modified request.
87     */
88    url = osip_message_get_uri(mymsg);
89    dest_port= (url->port)?atoi(url->port):SIP_PORT;
90
91    if (get_ip_by_host(url->host, &addr1) == STS_SUCCESS) {
92       if ((configuration.sip_listen_port == dest_port) &&
93           (url->username && (strcmp(url->username,"siproxd")==0)) &&
94           ((memcmp(&addr1, &addr2, sizeof(addr1)) == 0) ||
95            (memcmp(&addr1, &addr3, sizeof(addr1)) == 0))) {
96          /* Request URI points does to myself */
97          DEBUGC(DBCLASS_PROXY, "request URI [%s@%s:%i] points to myself",
98                 (url->username)?url->username:"*NULL*",
99                 (url->host)?url->host:"*NULL*",
100                 (url->port)?atoi(url->port):SIP_PORT);
101          /* get last route in list */
102          last=osip_list_size(mymsg->routes)-1;
103          route = (osip_route_t *) osip_list_get(mymsg->routes, last);
104          DEBUGC(DBCLASS_PROXY, "moving last Route [%s@%s:%i] to URI",
105                 (route->url->username)?route->url->username:"*NULL*",
106                 (route->url->host)?route->url->host:"*NULL*",
107                 (route->url->port)?atoi(route->url->port):SIP_PORT);
108
109          /* issue warning if the Route I'm going to fetch is NOT
110             a strict router (lr parameter not present) - something is fishy */
111          if (osip_uri_uparam_get_byname(route->url, "lr", &param) == 0) {
112             WARN("Fixup Strict Router: Route entry [%s@%s:%i] is not "
113                  "a strict Router!",
114                 (route->url->username)?route->url->username:"*NULL*",
115                 (route->url->host)?route->url->host:"*NULL*",
116                 (route->url->port)?atoi(route->url->port):SIP_PORT);
117          }
118
119          /* rewrite request URI */
120          osip_uri_free(url);
121          osip_uri_clone(route->url, &(mymsg->req_uri));
122
123          /* remove from list */
124          osip_list_remove(mymsg->routes, last);
125          osip_route_free(route);
126       }
127    } else {
128       WARN("cannot resolve host in Request URI [%s]", url->host);
129    }
130
131
132    /*
133     * 16.4 Route Information Preprocessing:
134     * If the first value in the Route header field indicates this proxy,
135     * the proxy MUST remove that value from the request.
136     */
137    DEBUGC(DBCLASS_PROXY, "route_preprocess: checking topmost "
138           "Route header");
139    route = (osip_route_t *) osip_list_get(mymsg->routes, 0);
140    if ((route != NULL) && (route->url != NULL) &&
141        (route->url->host != NULL)) {
142       sts = get_ip_by_host(route->url->host, &addr1);
143
144       /* my own route header? */
145       if ((sts == STS_SUCCESS) &&
146           ((memcmp(&addr1, &addr2, sizeof(addr1)) == 0) ||
147            (memcmp(&addr1, &addr3, sizeof(addr1)) == 0)) &&
148            (route->url->port ?
149                configuration.sip_listen_port == atoi(route->url->port):
150                configuration.sip_listen_port == SIP_PORT)) {
151          osip_list_remove(mymsg->routes, 0);
152          osip_route_free(route);
153          /* request->routes will be freed by osip_message_free() */
154          DEBUGC(DBCLASS_PROXY, "removed Route header pointing to myself");
155       }
156    }
157
158    return STS_SUCCESS;
159 }
160
161
162 /*
163  * PROXY_POSTPROCESS_ROUTE
164  *
165  * Route Information Postprocessing
166  * 
167  * RETURNS
168  *      STS_SUCCESS on success
169  */
170 int route_postprocess(sip_ticket_t *ticket){
171    osip_message_t *mymsg=ticket->sipmsg;
172    osip_uri_t *url;
173    osip_route_t *route=NULL;
174    osip_uri_param_t *param=NULL;
175
176    /*
177     * RFC 3261, Section 16.6 step 6
178     * Proxy Behavior - Request Forwarding - Postprocess routing information
179     *
180     * If the copy contains a Route header field, the proxy MUST
181     * inspect the URI in its first value.  If that URI does not
182     * contain an lr parameter, the proxy MUST modify the copy as
183     * follows:
184     *
185     * -  The proxy MUST place the Request-URI into the Route header
186     *    field as the last value.
187     *
188     * -  The proxy MUST then place the first Route header field value
189     *    into the Request-URI and remove that value from the Route
190     *    header field.
191     */
192
193    if (mymsg->routes && !osip_list_eol(mymsg->routes, 0)) {
194
195       route = (osip_route_t *) osip_list_get(mymsg->routes, 0);
196       if (route->url) {
197          /* check for non existing lr parameter */
198          if (osip_uri_uparam_get_byname(route->url, "lr", &param) != 0) {
199             osip_route_t *new_route=NULL;
200             url=osip_message_get_uri(mymsg);
201
202             /* push Request URI into Route header list at the last position */
203             osip_route_init(&new_route);
204             osip_uri_clone(url, &new_route->url);
205             osip_list_add(mymsg->routes, new_route, -1);
206
207             /* rewrite request URI to now topmost Route header */
208             DEBUGC(DBCLASS_PROXY, "Route header w/o 'lr': rewriting request "
209                    "URI from %s to %s", url->host, route->url->host);
210             osip_uri_free(url);
211             url=NULL;
212             osip_uri_clone(route->url, &url);
213             /* remove first Route header from list & free */
214             osip_list_remove(mymsg->routes, 0);
215             osip_route_free(route);
216             route = NULL;
217          }
218       }
219    }
220    return STS_SUCCESS;
221 }
222
223
224 /*
225  * PROXY_ADD_RECORDROUTE
226  *
227  * Add a Record-route header
228  * 
229  * RETURNS
230  *      STS_SUCCESS on success
231  */
232 int route_add_recordroute(sip_ticket_t *ticket){
233    osip_message_t *mymsg=ticket->sipmsg;
234    int sts;
235    int position;
236    struct in_addr addr;
237    osip_record_route_t *r_route;
238    osip_uri_t *uri_of_proxy;
239
240    /*
241     * RFC 3261, Section 16.6 step 4
242     * Proxy Behavior - Request Forwarding - Add a Record-route header
243     */
244
245    /*
246     * get the IP address of the interface where I'm going to
247     * send out this request
248     */
249    switch (ticket->direction) {
250    case REQTYP_INCOMING:
251    case RESTYP_INCOMING:
252       if (get_ip_by_ifname(configuration.inbound_if, &addr) != STS_SUCCESS) {
253          ERROR("can't find inbound interface %s - configuration error?",
254                configuration.inbound_if);
255          return STS_FAILURE;
256       }
257       break;
258    case REQTYP_OUTGOING:
259    case RESTYP_OUTGOING:
260       if (get_ip_by_ifname(configuration.outbound_if, &addr) != STS_SUCCESS) {
261          ERROR("can't find outbound interface %s - configuration error?",
262                configuration.outbound_if);
263          return STS_FAILURE;
264       }
265       break;
266    default:
267       ERROR("Oops, never should end up here (direction=%i)", ticket->direction);
268       return STS_FAILURE;
269    }
270
271    sts = osip_record_route_init(&r_route);
272    if (sts == 0) {
273       sts = osip_uri_init(&uri_of_proxy);
274       if (sts == 0) {
275          char tmp[8];
276
277          /* host name / IP */
278          osip_uri_set_host(uri_of_proxy, osip_strdup(utils_inet_ntoa(addr)));
279          osip_uri_set_username(uri_of_proxy, osip_strdup("siproxd"));
280
281          /* port number */
282          sprintf(tmp, "%i", configuration.sip_listen_port);
283          osip_uri_set_port(uri_of_proxy, osip_strdup(tmp));
284
285          /* 'lr' parameter */
286          osip_uri_uparam_add(uri_of_proxy, osip_strdup("lr"),NULL);
287
288          osip_record_route_set_url(r_route, uri_of_proxy);
289
290          position=0;
291          /* if it is a response, add in to the end of the list
292           * (reverse order as in request!) */
293          if ((ticket->direction==RESTYP_INCOMING) ||
294              (ticket->direction==RESTYP_OUTGOING)) {
295             position = -1;
296          }
297
298          /* insert into record-route list*/
299          osip_list_add (mymsg->record_routes, r_route, position);
300
301       } else {
302           osip_record_route_free(r_route);
303       } /* if url_init */
304    } /* if record route init */
305
306
307    return STS_SUCCESS;
308 }
309
310
311 /*
312  * PROXY_PURGE_RECORDROUTE
313  *
314  * Purge Record-Route headers pointing to myself.
315  * 
316  * RETURNS
317  *      STS_SUCCESS on success
318  */
319 int route_purge_recordroute(sip_ticket_t *ticket){
320    osip_message_t *mymsg=ticket->sipmsg;
321    osip_record_route_t *r_route=NULL;
322    int last, i, sts;
323    struct in_addr addr1, addr2, addr3;
324
325    if (mymsg->record_routes) {
326       last=osip_list_size(mymsg->record_routes)-1;
327       /* I *MUST NOT* purge any alien (non-mine) Record-Route headers,
328        * only the ones I've put in myself! */
329       if (last >= 0) {
330          for (i=last; i>=0; i--) {
331             r_route = (osip_record_route_t *)
332                       osip_list_get(mymsg->record_routes, i);
333
334             /* skip empty entries */
335             if (r_route == NULL) continue;
336             if (r_route->url == NULL) continue;
337             if (r_route->url->host == NULL) continue;
338
339             /* resolve IP addresses (of RR header, inbound & outbound IF) */
340             sts = get_ip_by_host(r_route->url->host, &addr1);
341             if (get_ip_by_ifname(configuration.inbound_if, &addr2) 
342                 != STS_SUCCESS) {
343                ERROR("can't find inbound interface %s - configuration error?",
344                      configuration.inbound_if);
345                return STS_FAILURE;
346             }
347             if (get_ip_by_ifname(configuration.outbound_if, &addr3)
348                 != STS_SUCCESS) {
349                ERROR("can't find outbound interface %s - configuration error?",
350                      configuration.outbound_if);
351                return STS_FAILURE;
352             }
353
354             /* check if my own route header? */
355             if ((sts == STS_SUCCESS) &&
356                 ((memcmp(&addr1, &addr2, sizeof(addr1)) == 0) ||
357                  (memcmp(&addr1, &addr3, sizeof(addr1)) == 0)) &&
358                  (r_route->url->port ?
359                      configuration.sip_listen_port == atoi(r_route->url->port):
360                      configuration.sip_listen_port == SIP_PORT)) {
361
362                osip_list_remove(mymsg->record_routes, i);
363                osip_record_route_free(r_route);
364                DEBUGC(DBCLASS_PROXY, "removed Record-Route header pointing "
365                       "to myself");
366             }
367          } // for
368       } // if
369    }
370    return STS_SUCCESS;
371 }
372
373
374 /*
375  * PROXY_DETERMINE_NEXT_HOP
376  *
377  * check if a route-header exists and give back the next hop
378  * 
379  * RETURNS
380  *      STS_SUCCESS on success
381  */
382 int route_determine_nexthop(sip_ticket_t *ticket,
383                             struct in_addr *dest, int *port){
384    int sts;
385    osip_message_t *mymsg=ticket->sipmsg;
386    osip_route_t *route=NULL;
387
388    /*
389    * Check for existing route header. If so, the topmost will be
390    * the next hop.
391    *
392    * If this route header does NOT have a lr parameter set, rewrite
393    * the SIP URI to point to the destination of the route (NOT IMPLEMENTED)
394    */
395    if (mymsg->routes && !osip_list_eol(mymsg->routes, 0)) {
396
397       /* get the destination from the Route Header */
398       route = (osip_route_t *) osip_list_get(mymsg->routes, 0);
399       if (route==NULL || route->url==NULL || route->url->host==NULL) {
400          DEBUGC(DBCLASS_PROXY, "route_determine_nexthop: got broken Route "
401                 "header - discarding packet");
402          return STS_FAILURE;
403       }
404
405       sts = get_ip_by_host(route->url->host, dest);
406       if (sts == STS_FAILURE) {
407          DEBUGC(DBCLASS_PROXY, "route_determine_nexthop: cannot resolve "
408                 "Route URI [%s]", route->url->host);
409          return STS_FAILURE;
410       }
411
412       if (route->url->port) {
413          *port=atoi(route->url->port);
414       } else {
415          *port=SIP_PORT;
416       }
417
418       osip_list_remove(mymsg->routes, 0);
419       osip_route_free(route);
420       /* request->routes will be freed by osip_message_free() */
421    }
422
423    return STS_SUCCESS;
424 }