/* * Do loose routing as defined in RFC3621 */ int loose_route(struct sip_msg* _m, char* _s1, char* _s2) { struct hdr_field* hdr; struct sip_uri puri; rr_t* rt; int ret; str* uri; if (find_first_route(_m) != 0) { DBG("loose_route: There is no Route HF\n"); return -1; } if (parse_sip_msg_uri(_m) == -1) { LOG(L_ERR, "loose_route: Error while parsing Request URI\n"); return -1; } hdr = _m->route; rt = (rr_t*)hdr->parsed; uri = &rt->nameaddr.uri; if (parse_uri(uri->s, uri->len, &puri) < 0) { LOG(L_ERR, "loose_route: Error while parsing the first route URI\n"); return -1; } if (is_myself(&_m->parsed_uri.host, _m->parsed_uri.port_no)|| _m->parsed_uri.type == TEL_URI_T || _m->parsed_uri.type == TELS_URI_T) { DBG("loose_route: RURI is myself (or tel URI)\n"); if ((ret = is_myself(&puri.host, puri.port_no)) == 1 && !(enable_double_rr && is_2rr(&puri.params))) { DBG("loose_route: found preloaded loose route\n"); return after_loose(_m, &puri, ret, 1); } else { if (has_to_tag(_m) == 1) { return after_strict(_m, &puri, ret); } else { LOG(L_WARN, "loose_route: pre-loaded strict routing?!\n"); return -1; } } } else { DBG("loose_route: RURI is NOT myself\n"); if (is_myself(&puri.host, puri.port_no)) { return after_loose(_m, &puri, 1, 0); } else { store_next_route_in_avps(uri); //LOG(L_WARN, "loose_route: no routing target is local\n"); //return -1; return after_loose(_m, &puri, 0, 0); } } }
/*! * \brief Previous hop was a loose router, handle this case * \param _m SIP message * \param preloaded do we have a preloaded route set * \return -1 on failure, 1 on success */ static inline int after_loose(struct sip_msg* _m, int preloaded) { struct hdr_field* hdr; struct sip_uri puri; rr_t* rt; int res; int status = RR_DRIVEN; str uri; struct socket_info *si; int uri_is_myself, next_is_strict; int use_ob = 0; hdr = _m->route; rt = (rr_t*)hdr->parsed; uri = rt->nameaddr.uri; /* reset rr handling static vars for safety in error case */ routed_msg_id = 0; if (parse_uri(uri.s, uri.len, &puri) < 0) { LM_ERR("failed to parse the first route URI\n"); return RR_ERROR; } next_is_strict = is_strict(&puri.params); routed_params = puri.params; uri_is_myself = is_myself(&puri); /* IF the URI was added by me, remove it */ if (uri_is_myself>0) { LM_DBG("Topmost route URI: '%.*s' is me\n", uri.len, ZSW(uri.s)); /* set the hooks for the params */ routed_msg_id = _m->id; if ((use_ob = process_outbound(_m, puri.user)) < 0) { LM_INFO("failed to process outbound flow-token\n"); return FLOW_TOKEN_BROKEN; } if (!rt->next) { /* No next route in the same header, remove the whole header * field immediately */ if (!del_lump(_m, hdr->name.s - _m->buf, hdr->len, 0)) { LM_ERR("failed to remove Route HF\n"); return RR_ERROR; } res = find_next_route(_m, &hdr); if (res < 0) { LM_ERR("failed to find next route\n"); return RR_ERROR; } if (res > 0) { /* No next route found */ LM_DBG("No next URI found\n"); status = (preloaded ? NOT_RR_DRIVEN : RR_DRIVEN); goto done; } rt = (rr_t*)hdr->parsed; } else rt = rt->next; if (enable_double_rr && is_2rr(&puri.params)) { /* double route may occure due different IP and port, so force as * send interface the one advertise in second Route */ if (parse_uri(rt->nameaddr.uri.s,rt->nameaddr.uri.len,&puri)<0) { LM_ERR("failed to parse the double route URI\n"); return RR_ERROR; } if (!use_ob) { si = grep_sock_info( &puri.host, puri.port_no, puri.proto); if (si) { set_force_socket(_m, si); } else { if (enable_socket_mismatch_warning) LM_WARN("no socket found for match second RR\n"); } } if (!rt->next) { /* No next route in the same header, remove the whole header * field immediately */ if (!del_lump(_m, hdr->name.s - _m->buf, hdr->len, 0)) { LM_ERR("failed to remove Route HF\n"); return RR_ERROR; } res = find_next_route(_m, &hdr); if (res < 0) { LM_ERR("failed to find next route\n"); return RR_ERROR; } if (res > 0) { /* No next route found */ LM_DBG("no next URI found\n"); status = (preloaded ? NOT_RR_DRIVEN : RR_DRIVEN); goto done; } rt = (rr_t*)hdr->parsed; } else rt = rt->next; } uri = rt->nameaddr.uri; if (parse_uri(uri.s, uri.len, &puri) < 0) { LM_ERR("failed to parse the first route URI\n"); return RR_ERROR; } } else { #ifdef ENABLE_USER_CHECK /* check if it the ignored user */ if(uri_is_myself < 0) return NOT_RR_DRIVEN; #endif LM_DBG("Topmost URI is NOT myself\n"); routed_params.s = NULL; routed_params.len = 0; } LM_DBG("URI to be processed: '%.*s'\n", uri.len, ZSW(uri.s)); if (next_is_strict) { LM_DBG("Next URI is a strict router\n"); if (handle_sr(_m, hdr, rt) < 0) { LM_ERR("failed to handle strict router\n"); return RR_ERROR; } } else { /* Next hop is loose router */ LM_DBG("Next URI is a loose router\n"); if (!use_ob) { if(get_maddr_uri(&uri, &puri)!=0) { LM_ERR("checking maddr failed\n"); return RR_ERROR; } if (set_dst_uri(_m, &uri) < 0) { LM_ERR("failed to set dst_uri\n"); return RR_ERROR; } /* dst_uri changed, so it makes sense to re-use the current uri for forking */ ruri_mark_new(); /* re-use uri for serial forking */ } /* There is a previous route uri which was 2nd uri of mine * and must be removed here */ if (rt != hdr->parsed) { if (!del_lump(_m, hdr->body.s - _m->buf, rt->nameaddr.name.s - hdr->body.s, 0)) { LM_ERR("failed to remove Route HF\n"); return RR_ERROR; } } } done: if (use_ob == 1) status = RR_OB_DRIVEN; /* run RR callbacks only if we have Route URI parameters */ if(routed_params.len > 0) run_rr_callbacks( _m, &routed_params ); return status; }
/*! * \brief Previous hop was a strict router, handle this case * \param _m SIP message * \return -1 on error, 1 on success */ static inline int after_strict(struct sip_msg* _m) { int res, rem_len; struct hdr_field* hdr; struct sip_uri puri; rr_t* rt, *prev; char* rem_off; str uri; struct socket_info *si; hdr = _m->route; rt = (rr_t*)hdr->parsed; uri = rt->nameaddr.uri; /* reset rr handling static vars for safety in error case */ routed_msg_id = 0; routed_params.s = NULL; routed_params.len = 0; if (parse_uri(uri.s, uri.len, &puri) < 0) { LM_ERR("failed to parse the first route URI\n"); return RR_ERROR; } if ( enable_double_rr && is_2rr(&puri.params) && is_myself(&puri)) { /* double route may occure due different IP and port, so force as * send interface the one advertise in second Route */ si = grep_sock_info( &puri.host, puri.port_no, puri.proto); if (si) { set_force_socket(_m, si); } else { if (enable_socket_mismatch_warning) LM_WARN("no socket found for match second RR\n"); } if (!rt->next) { /* No next route in the same header, remove the whole header * field immediately */ if (!del_lump(_m, hdr->name.s - _m->buf, hdr->len, 0)) { LM_ERR("failed to remove Route HF\n"); return RR_ERROR; } res = find_next_route(_m, &hdr); if (res < 0) { LM_ERR("searching next route failed\n"); return RR_ERROR; } if (res > 0) { /* No next route found */ LM_DBG("after_strict: No next URI found\n"); return NOT_RR_DRIVEN; } rt = (rr_t*)hdr->parsed; } else rt = rt->next; /* parse the new found uri */ uri = rt->nameaddr.uri; if (parse_uri(uri.s, uri.len, &puri) < 0) { LM_ERR("failed to parse URI\n"); return RR_ERROR; } } /* set the hooks for the param * important note: RURI is already parsed by the above function, so * we just used it without any checking */ routed_msg_id = _m->id; routed_params = _m->parsed_uri.params; if (is_strict(&puri.params)) { LM_DBG("Next hop: '%.*s' is strict router\n", uri.len, ZSW(uri.s)); /* Previous hop was a strict router and the next hop is strict * router too. There is no need to save R-URI again because it * is saved already. In fact, in this case we will behave exactly * like a strict router. */ /* Note: when there is only one Route URI left (endpoint), it will * always be a strict router because endpoints don't use ;lr parameter * In this case we will simply put the URI in R-URI and forward it, * which will work perfectly */ if(get_maddr_uri(&uri, &puri)!=0) { LM_ERR("failed to check maddr\n"); return RR_ERROR; } if (rewrite_uri(_m, &uri) < 0) { LM_ERR("failed to rewrite request URI\n"); return RR_ERROR; } if (rt->next) { rem_off = hdr->body.s; rem_len = rt->next->nameaddr.name.s - hdr->body.s; } else { rem_off = hdr->name.s; rem_len = hdr->len; } if (!del_lump(_m, rem_off - _m->buf, rem_len, 0)) { LM_ERR("failed to remove Route HF\n"); return RR_ERROR; } } else { LM_DBG("Next hop: '%.*s' is loose router\n", uri.len, ZSW(uri.s)); if(get_maddr_uri(&uri, &puri)!=0) { LM_ERR("failed to check maddr\n"); return RR_ERROR; } if (set_dst_uri(_m, &uri) < 0) { LM_ERR("failed to set dst_uri\n"); return RR_ERROR; } /* Next hop is a loose router - Which means that is is not endpoint yet * In This case we have to recover from previous strict routing, that * means we have to find the last Route URI and put in in R-URI and * remove the last Route URI. */ if (rt != hdr->parsed) { /* There is a previous route uri which was 2nd uri of mine * and must be removed here */ rem_off = hdr->body.s; rem_len = rt->nameaddr.name.s - hdr->body.s; if (!del_lump(_m, rem_off - _m->buf, rem_len, 0)) { LM_ERR("failed to remove Route HF\n"); return RR_ERROR; } } res = find_rem_target(_m, &hdr, &rt, &prev); if (res < 0) { LM_ERR("searching for last Route URI failed\n"); return RR_ERROR; } else if (res > 0) { /* No remote target is an error */ return RR_ERROR; } uri = rt->nameaddr.uri; if(get_maddr_uri(&uri, 0)!=0) { LM_ERR("checking maddr failed\n"); return RR_ERROR; } if (rewrite_uri(_m, &uri) < 0) { LM_ERR("failed to rewrite R-URI\n"); return RR_ERROR; } /* The first character if uri will be either '<' when it is the * only URI in a Route header field or ',' if there is more than * one URI in the header field */ LM_DBG("The last route URI: '%.*s'\n", rt->nameaddr.uri.len, ZSW(rt->nameaddr.uri.s)); if (prev) { rem_off = prev->nameaddr.name.s + prev->len; rem_len = rt->nameaddr.name.s + rt->len - rem_off; } else { rem_off = hdr->name.s; rem_len = hdr->len; } if (!del_lump(_m, rem_off - _m->buf, rem_len, 0)) { LM_ERR("failed to remove Route HF\n"); return RR_ERROR; } } /* run RR callbacks only if we have Route URI parameters */ if(routed_params.len > 0) run_rr_callbacks( _m, &routed_params ); return RR_DRIVEN; }
static inline int after_loose(struct sip_msg* _m, int preloaded) { struct hdr_field* hdr; struct sip_uri puri; struct sip_uri puri2; rr_t* rt; int res; int status; #ifdef ENABLE_USER_CHECK int ret; #endif str uri; struct socket_info *si; int force_ss = 0; hdr = _m->route; rt = (rr_t*)hdr->parsed; uri = rt->nameaddr.uri; if (parse_uri(uri.s, uri.len, &puri) < 0) { LM_ERR("failed to parse the first route URI\n"); return RR_ERROR; } /* IF the URI was added by me, remove it */ #ifdef ENABLE_USER_CHECK ret=is_myself(&puri.user, &puri.host, puri.port_no); if (ret>0) #else if (is_myself(&puri.host, puri.port_no)) #endif { LM_DBG("Topmost route URI: '%.*s' is me\n", uri.len, ZSW(uri.s)); /* set the hooks for the params -bogdan */ ctx_rrparam_set( &puri.params ); /* if last route in header, gonna get del_lumped now, * if not, it will be taken care of later * Mark it now as deleted */ rt->deleted = 1; if (!rt->next) { /* No next route in the same header, remove the whole header * field immediately */ if (!del_lump(_m, hdr->name.s - _m->buf, hdr->len, 0)) { LM_ERR("failed to remove Route HF\n"); return RR_ERROR; } rt->deleted = 1; res = find_next_route(_m, &hdr); if (res < 0) { LM_ERR("failed to find next route\n"); return RR_ERROR; } if (res > 0) { /* No next route found */ LM_DBG("No next URI found!\n"); status = (preloaded ? NOT_RR_DRIVEN : RR_DRIVEN); /*same case as LL , if there is no next route*/ ctx_routing_set( ROUTING_LL ); force_ss = 1; goto done; } rt = (rr_t*)hdr->parsed; } else rt = rt->next; if (enable_double_rr && is_2rr(&puri.params)) { force_ss = 0; /* double route may occure due different IP and port, so force as * send interface the one advertise in second Route */ if (parse_uri(rt->nameaddr.uri.s,rt->nameaddr.uri.len,&puri)<0) { LM_ERR("failed to parse the double route URI\n"); return RR_ERROR; } set_sip_defaults( puri.port_no, puri.proto); si = grep_sock_info( &puri.host, puri.port_no, puri.proto); if (si) { _m->force_send_socket = si; } else { if (enable_socket_mismatch_warning) LM_WARN("no socket found to match 2nd RR [%d][%.*s:%d]\n", puri.proto, puri.host.len, puri.host.s, puri.port_no); } rt->deleted = 1; if (!rt->next) { /* No next route in the same header, remove the whole header * field immediately */ if (!del_lump(_m, hdr->name.s - _m->buf, hdr->len, 0)) { LM_ERR("failed to remove Route HF\n"); return RR_ERROR; } res = find_next_route(_m, &hdr); if (res < 0) { LM_ERR("failed to find next route\n"); return RR_ERROR; } if (res > 0) { /* No next route found */ LM_DBG("no next URI found\n"); status = (preloaded ? NOT_RR_DRIVEN : RR_DRIVEN); /* same case as LL , if there is no next route */ ctx_routing_set( ROUTING_LL ); goto done; } rt = (rr_t*)hdr->parsed; } else rt = rt->next; } else { force_ss = 1; } uri = rt->nameaddr.uri; if (parse_uri(uri.s, uri.len, &puri2) < 0) { LM_ERR("failed to parse the first route URI\n"); return RR_ERROR; } } else { #ifdef ENABLE_USER_CHECK /* check if it the ignored user */ if(ret < 0) return NOT_RR_DRIVEN; #endif LM_DBG("Topmost URI is NOT myself\n"); memcpy(&puri2, &puri, sizeof(struct sip_uri)); } LM_DBG("URI to be processed: '%.*s'\n", uri.len, ZSW(uri.s)); if (is_strict(&puri2.params)) { LM_DBG("Next URI is a strict router\n"); ctx_routing_set( ROUTING_LS ); if (handle_sr(_m, hdr, rt) < 0) { LM_ERR("failed to handle strict router\n"); return RR_ERROR; } } else { /* Next hop is loose router */ LM_DBG("Next URI is a loose router\n"); ctx_routing_set( ROUTING_LL ); if(get_maddr_uri(&uri, &puri2)!=0) { LM_ERR("checking maddr failed\n"); return RR_ERROR; } if (set_dst_uri(_m, &uri) < 0) { LM_ERR("failed to set dst_uri\n"); return RR_ERROR; } /* There is a previous route uri which was 2nd uri of mine * and must be removed here */ if (rt != hdr->parsed) { if (!del_lump(_m, hdr->body.s - _m->buf, rt->nameaddr.name.s - hdr->body.s, 0)) { LM_ERR("failed to remove Route HF\n"); return RR_ERROR; } ((rr_t *)hdr->parsed)->deleted = 1; } } status = RR_DRIVEN; done: if (force_ss && !preloaded) _m->force_send_socket = _m->rcv.bind_address; /* run RR callbacks -bogdan */ run_rr_callbacks( _m, &puri.params ); return status; }
static inline int after_loose(struct sip_msg* _m, struct sip_uri* _pru, int _route_myself, int _ruri_myself) { struct hdr_field* hdr; rr_t* rt; int res; #ifdef ENABLE_USER_CHECK int ret; #endif str* uri; str avp_cookie; hdr = _m->route; rt = (rr_t*)hdr->parsed; uri = &rt->nameaddr.uri; /* IF the URI was added by me, remove it */ if (_route_myself == 1) { store_user_in_avps(&(_pru->user)); DBG("after_loose: Topmost route URI: '%.*s' is me\n", uri->len, ZSW(uri->s)); get_avp_cookie_from_uri(&(_pru->params), &avp_cookie); if (avp_cookie.len > 0) rr_set_avp_cookies(&avp_cookie, get_direction(_m, &(_pru->params))); if (!rt->next) { /* No next route in the same header, remove the whole header * field immediately */ if (!del_lump(_m, hdr->name.s - _m->buf, hdr->len, 0)) { LOG(L_ERR, "after_loose: Can't remove Route HF\n"); return RR_ERROR; } res = find_next_route(_m, &hdr); if (res < 0) { LOG(L_ERR, "after_loose: Error while finding next route\n"); return RR_ERROR; } if (res > 0) { /* No next route found */ DBG("after_loose: No next URI found\n"); if (_ruri_myself == 1) { /* this a preloaded request. we do not check for the To-tag * because the ACK for a negative reply will contain such * a tag but the original INVITE not */ return NOT_RR_DRIVEN; } else { return RR_DRIVEN; } } rt = (rr_t*)hdr->parsed; } else rt = rt->next; if (enable_double_rr && is_2rr(&(_pru->params))) { if (!rt->next) { /* No next route in the same header, remove the whole header * field immediately */ if (!del_lump(_m, hdr->name.s - _m->buf, hdr->len, 0)) { LOG(L_ERR, "after_loose: Can't remove Route HF\n"); return RR_ERROR; } res = find_next_route(_m, &hdr); if (res < 0) { LOG(L_ERR, "after_loose: Error while finding next route\n"); return RR_ERROR; } if (res > 0) { /* No next route found */ DBG("after_loose: No next URI found\n"); /* preloaded routes can not happen with double_rr, so * we were just the last hop with double_rr */ return RR_DRIVEN; } rt = (rr_t*)hdr->parsed; } else rt = rt->next; } if(rt != _m->route->parsed) { uri = &rt->nameaddr.uri; if (parse_uri(uri->s, uri->len, _pru) < 0) { LOG(L_ERR, "after_loose: Error while parsing the next route URI\n"); return RR_ERROR; } } } else { #ifdef ENABLE_USER_CHECK /* check if it the ignored user */ if(ret < 0) return NOT_RR_DRIVEN; #endif DBG("after_loose: Topmost URI is NOT myself\n"); } store_next_route_in_avps(uri); DBG("after_loose: URI to be processed: '%.*s'\n", uri->len, ZSW(uri->s)); if (is_strict(&(_pru->params))) { DBG("after_loose: Next URI is a strict router\n"); if (handle_sr(_m, hdr, rt) < 0) { LOG(L_ERR, "after_loose: Error while handling strict router\n"); return RR_ERROR; } } else { /* Next hop is loose router */ DBG("after_loose: Next URI is a loose router\n"); if (set_dst_uri(_m, uri) < 0) { LOG(L_ERR, "after_loose: Error while setting dst_uri\n"); return RR_ERROR; } /* There is a previous route uri which was 2nd uri of mine * and must be removed here */ if (rt != hdr->parsed) { if (!del_lump(_m, hdr->body.s - _m->buf, rt->nameaddr.name.s - hdr->body.s, 0)) { LOG(L_ERR, "after_loose: Can't remove Route HF\n"); return RR_ERROR; } } } return RR_DRIVEN; }