1 /* -*- Mode: C; c-basic-offset: 3 -*-
2 Copyright (C) 2002-2005 Thomas Ries <tries@gmx.net>
4 This file is part of Siproxd.
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.
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.
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
27 #include <sys/types.h>
28 #include <netinet/in.h>
29 #include <arpa/inet.h>
32 #include <osipparser2/osip_parser.h>
33 #include <osipparser2/sdp_message.h>
38 static char const ident[]="$Id: route_processing.c,v 1.1.1.1 2006/05/18 10:47:25 michaelc Exp $";
40 /* configuration storage */
41 extern struct siproxd_config configuration; /* defined in siproxd.c */
45 * PROXY_PREPROCESS_ROUTE
47 * Route Information Preprocessing
50 * STS_SUCCESS on success
52 int route_preprocess(sip_ticket_t *ticket){
53 osip_message_t *mymsg=ticket->sipmsg;
58 struct in_addr addr1, addr2, addr3;
60 osip_uri_param_t *param=NULL;
62 if ((mymsg->routes==NULL) || (osip_list_size(mymsg->routes)<=0)) {
63 DEBUGC(DBCLASS_PROXY, "route_preprocess: no Route header present");
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);
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);
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.
88 url = osip_message_get_uri(mymsg);
89 dest_port= (url->port)?atoi(url->port):SIP_PORT;
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);
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", ¶m) == 0) {
112 WARN("Fixup Strict Router: Route entry [%s@%s:%i] is not "
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);
119 /* rewrite request URI */
121 osip_uri_clone(route->url, &(mymsg->req_uri));
123 /* remove from list */
124 osip_list_remove(mymsg->routes, last);
125 osip_route_free(route);
128 WARN("cannot resolve host in Request URI [%s]", url->host);
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.
137 DEBUGC(DBCLASS_PROXY, "route_preprocess: checking topmost "
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);
144 /* my own route header? */
145 if ((sts == STS_SUCCESS) &&
146 ((memcmp(&addr1, &addr2, sizeof(addr1)) == 0) ||
147 (memcmp(&addr1, &addr3, sizeof(addr1)) == 0)) &&
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");
163 * PROXY_POSTPROCESS_ROUTE
165 * Route Information Postprocessing
168 * STS_SUCCESS on success
170 int route_postprocess(sip_ticket_t *ticket){
171 osip_message_t *mymsg=ticket->sipmsg;
173 osip_route_t *route=NULL;
174 osip_uri_param_t *param=NULL;
177 * RFC 3261, Section 16.6 step 6
178 * Proxy Behavior - Request Forwarding - Postprocess routing information
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
185 * - The proxy MUST place the Request-URI into the Route header
186 * field as the last value.
188 * - The proxy MUST then place the first Route header field value
189 * into the Request-URI and remove that value from the Route
193 if (mymsg->routes && !osip_list_eol(mymsg->routes, 0)) {
195 route = (osip_route_t *) osip_list_get(mymsg->routes, 0);
197 /* check for non existing lr parameter */
198 if (osip_uri_uparam_get_byname(route->url, "lr", ¶m) != 0) {
199 osip_route_t *new_route=NULL;
200 url=osip_message_get_uri(mymsg);
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);
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);
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);
225 * PROXY_ADD_RECORDROUTE
227 * Add a Record-route header
230 * STS_SUCCESS on success
232 int route_add_recordroute(sip_ticket_t *ticket){
233 osip_message_t *mymsg=ticket->sipmsg;
237 osip_record_route_t *r_route;
238 osip_uri_t *uri_of_proxy;
241 * RFC 3261, Section 16.6 step 4
242 * Proxy Behavior - Request Forwarding - Add a Record-route header
246 * get the IP address of the interface where I'm going to
247 * send out this request
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);
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);
267 ERROR("Oops, never should end up here (direction=%i)", ticket->direction);
271 sts = osip_record_route_init(&r_route);
273 sts = osip_uri_init(&uri_of_proxy);
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"));
282 sprintf(tmp, "%i", configuration.sip_listen_port);
283 osip_uri_set_port(uri_of_proxy, osip_strdup(tmp));
286 osip_uri_uparam_add(uri_of_proxy, osip_strdup("lr"),NULL);
288 osip_record_route_set_url(r_route, uri_of_proxy);
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)) {
298 /* insert into record-route list*/
299 osip_list_add (mymsg->record_routes, r_route, position);
302 osip_record_route_free(r_route);
304 } /* if record route init */
312 * PROXY_PURGE_RECORDROUTE
314 * Purge Record-Route headers pointing to myself.
317 * STS_SUCCESS on success
319 int route_purge_recordroute(sip_ticket_t *ticket){
320 osip_message_t *mymsg=ticket->sipmsg;
321 osip_record_route_t *r_route=NULL;
323 struct in_addr addr1, addr2, addr3;
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! */
330 for (i=last; i>=0; i--) {
331 r_route = (osip_record_route_t *)
332 osip_list_get(mymsg->record_routes, i);
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;
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)
343 ERROR("can't find inbound interface %s - configuration error?",
344 configuration.inbound_if);
347 if (get_ip_by_ifname(configuration.outbound_if, &addr3)
349 ERROR("can't find outbound interface %s - configuration error?",
350 configuration.outbound_if);
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)) {
362 osip_list_remove(mymsg->record_routes, i);
363 osip_record_route_free(r_route);
364 DEBUGC(DBCLASS_PROXY, "removed Record-Route header pointing "
375 * PROXY_DETERMINE_NEXT_HOP
377 * check if a route-header exists and give back the next hop
380 * STS_SUCCESS on success
382 int route_determine_nexthop(sip_ticket_t *ticket,
383 struct in_addr *dest, int *port){
385 osip_message_t *mymsg=ticket->sipmsg;
386 osip_route_t *route=NULL;
389 * Check for existing route header. If so, the topmost will be
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)
395 if (mymsg->routes && !osip_list_eol(mymsg->routes, 0)) {
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");
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);
412 if (route->url->port) {
413 *port=atoi(route->url->port);
418 osip_list_remove(mymsg->routes, 0);
419 osip_route_free(route);
420 /* request->routes will be freed by osip_message_free() */