static int rewrite_route_set(pjsip_rx_data *rdata, pjsip_dialog *dlg) { pjsip_rr_hdr *rr = NULL; pjsip_sip_uri *uri; if (rdata->msg_info.msg->type == PJSIP_RESPONSE_MSG) { pjsip_hdr *iter; for (iter = rdata->msg_info.msg->hdr.prev; iter != &rdata->msg_info.msg->hdr; iter = iter->prev) { if (iter->type == PJSIP_H_RECORD_ROUTE) { rr = (pjsip_rr_hdr *)iter; break; } } } else if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_register_method)) { rr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_RECORD_ROUTE, NULL); } if (rr) { uri = pjsip_uri_get_uri(&rr->name_addr); rewrite_uri(rdata, uri); if (dlg && !pj_list_empty(&dlg->route_set) && !dlg->route_set_frozen) { pjsip_routing_hdr *route = dlg->route_set.next; uri = pjsip_uri_get_uri(&route->name_addr); rewrite_uri(rdata, uri); } return 0; } return -1; }
static PyObject *msg_rewrite_ruri(msgobject *self, PyObject *args) { str nuri; if (self == NULL) { PyErr_SetString(PyExc_RuntimeError, "self is NULL"); Py_INCREF(Py_None); return Py_None; } if (self->msg == NULL) { PyErr_SetString(PyExc_RuntimeError, "self->msg is NULL"); Py_INCREF(Py_None); return Py_None; } if ((self->msg->first_line).type != SIP_REQUEST) { PyErr_SetString(PyExc_RuntimeError, "Not a request message - rewrite is not possible.\n"); Py_INCREF(Py_None); return Py_None; } if(!PyArg_ParseTuple(args, "s:rewrite_ruri", &nuri.s)) return NULL; nuri.len = strlen(nuri.s); if(rewrite_uri(self->msg, &nuri)<0) { LM_ERR("failed to update r-uri with [%.*s]\n", nuri.len, nuri.s); } Py_INCREF(Py_None); return Py_None; }
/* * Logic necessary to forward request to strict routers * * Returns 0 on success, negative number on an error */ static inline int handle_sr(struct sip_msg* _m, struct hdr_field* _hdr, rr_t* _r) { str* uri; char* rem_off; int rem_len; uri = &_r->nameaddr.uri; /* Next hop is strict router, save R-URI here */ if (save_ruri(_m) < 0) { LOG(L_ERR, "handle_sr: Error while saving Request-URI\n"); return -1; } /* Put the first Route in Request-URI */ if (rewrite_uri(_m, uri) < 0) { LOG(L_ERR, "handle_sr: Error while rewriting request URI\n"); return -2; } if (!_r->next) { rem_off = _hdr->name.s; rem_len = _hdr->len; } else { rem_off = _hdr->body.s; rem_len = _r->next->nameaddr.name.s - _hdr->body.s; } if (!del_lump(_m, rem_off - _m->buf, rem_len, 0)) { LOG(L_ERR, "handle_sr: Can't remove Route HF\n"); return -9; } return 0; }
/* * Converts Request-URI, if it is tel URI, to SIP URI. Returns 1, if * conversion succeeded or if no conversion was needed, i.e., Request-URI * was not tel URI. Returns -1, if conversion failed. */ int tel2sip(struct sip_msg* _msg, char* _s1, char* _s2) { str *ruri, furi; struct sip_uri pfuri; str suri; char* at; ruri = GET_RURI(_msg); if (ruri->len < 4) return 1; if (strncmp(ruri->s, "tel:", 4) != 0) return 1; if (parse_from_header(_msg) < 0) { LOG(L_ERR, "tel2sip(): Error while parsing From header\n"); return -1; } furi = get_from(_msg)->uri; if (parse_uri(furi.s, furi.len, &pfuri) < 0) { LOG(L_ERR, "tel2sip(): Error while parsing From URI\n"); return -1; } suri.len = 4 + ruri->len - 4 + 1 + pfuri.host.len + 1 + 10; suri.s = pkg_malloc(suri.len); if (suri.s == 0) { LOG(L_ERR, "tel2sip(): Memory allocation failure\n"); return -1; } at = suri.s; memcpy(at, "sip:", 4); at = at + 4; memcpy(at, ruri->s + 4, ruri->len - 4); at = at + ruri->len - 4; *at = '@'; at = at + 1; memcpy(at, pfuri.host.s, pfuri.host.len); at = at + pfuri.host.len; *at = ';'; at = at + 1; memcpy(at, "user=phone", 10); LOG(L_ERR, "tel2sip(): SIP URI is <%.*s>\n", suri.len, suri.s); if (rewrite_uri(_msg, &suri) == 1) { pkg_free(suri.s); return 1; } else { pkg_free(suri.s); return -1; } }
/* * Build SIP message for destination * param msg SIP message * param isfirst Is first destination * param type Main or branch route block * param format URI format * return MODULE_RETURNCODE_TRUE success MODULE_RETURNCODE_FALSE failure */ static int ospPrepareDestination( struct sip_msg* msg, int isfirst, int type, int format) { str newuri = {NULL, 0}; int result = MODULE_RETURNCODE_FALSE; LOG(L_DBG, "osp: ospPrepareDestination\n"); osp_dest *dest = ospGetNextOrigDestination(); if (dest != NULL) { ospRebuildDestionationUri(&newuri, dest->called, dest->host, "", format); LOG(L_INFO, "osp: prepare route to URI '%.*s' for call_id '%.*s' transaction_id '%llu'\n", newuri.len, newuri.s, dest->callidsize, dest->callid, dest->transid); if (type == OSP_MAIN_ROUTE) { if (isfirst == OSP_FIRST_ROUTE) { rewrite_uri(msg, &newuri); } else { append_branch(msg, &newuri, NULL, NULL, Q_UNSPECIFIED, 0, NULL); } result = MODULE_RETURNCODE_TRUE; } else { LOG(L_ERR, "osp: ERROR: unsupported route block type\n"); } } else { LOG(L_DBG, "osp: there is no more routes\n"); ospReportOrigSetupUsage(); } if (newuri.len > 0) { pkg_free(newuri.s); } return result; }
static enum evhook_status goto_url_hook(va_list ap, void *data) { unsigned char **url = va_arg(ap, unsigned char **); struct session *ses = va_arg(ap, struct session *); unsigned char *uu = NULL; unsigned char *arg = ""; unsigned char *argstart = *url + strcspn(*url, " :"); if (get_smart_enable() && *argstart) { unsigned char bucket = *argstart; *argstart = '\0'; uu = get_uri_rewrite_prefix(URI_REWRITE_SMART, *url); *argstart = bucket; arg = argstart + 1; } if (get_dumb_enable() && !uu && !*argstart) uu = get_uri_rewrite_prefix(URI_REWRITE_DUMB, *url); if (!uu && !strchr((const char *)*url, ':') && !strchr((const char *)*url, '.') && !strchr((const char *)*url, '/')) { uu = get_opt_str("protocol.rewrite.default_template", NULL); if (uu && *uu) { arg = *url; } else { uu = NULL; } } if (uu) { struct uri *uri = ses && have_location(ses) ? cur_loc(ses)->vs.uri : NULL; uu = rewrite_uri(uu, uri, arg); if (uu) { mem_free(*url); *url = uu; } } return EVENT_HOOK_STATUS_NEXT; }
int set_alias_to_ruri(struct sip_msg* _msg, str *alias, int no, void *p) { /* set the RURI */ if(no==0) { if(rewrite_uri(_msg, alias)<0) { LM_ERR("cannot replace the R-URI\n"); return -1; } } else if (ald_append_branches) { if (append_branch(_msg, alias, 0, 0, MIN_Q, 0, 0, 0, 0, 0, 0) == -1) { LM_ERR("error while appending branches\n"); return -1; } } return 0; }
static int rewrite_contact(pjsip_rx_data *rdata, pjsip_dialog *dlg) { pjsip_contact_hdr *contact; contact = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, NULL); if (contact && !contact->star && (PJSIP_URI_SCHEME_IS_SIP(contact->uri) || PJSIP_URI_SCHEME_IS_SIPS(contact->uri))) { pjsip_sip_uri *uri = pjsip_uri_get_uri(contact->uri); rewrite_uri(rdata, uri); if (dlg && pj_list_empty(&dlg->route_set) && (!dlg->remote.contact || pjsip_uri_cmp(PJSIP_URI_IN_REQ_URI, dlg->remote.contact->uri, contact->uri))) { dlg->remote.contact = (pjsip_contact_hdr*)pjsip_hdr_clone(dlg->pool, contact); dlg->target = dlg->remote.contact->uri; } return 0; } return -1; }
/** * Creates new "main" branch by making copy of branch-failure branch. * Currently the following branch attributes are included: * request-uri, ruid, path, instance, and branch flags. */ static int w_t_reuse_branch(sip_msg_t* msg, char *p1, char *p2) { tm_cell_t *t; int branch; if (msg == NULL) return -1; /* first get the transaction */ if (_tmx_tmb.t_check(msg, 0) == -1) return -1; if ((t = _tmx_tmb.t_gett()) == 0) { LM_ERR("no transaction\n"); return -1; } switch (get_route_type()) { case BRANCH_FAILURE_ROUTE: /* use the reason of the winning reply */ if ((branch = _tmx_tmb.t_get_picked_branch()) < 0) { LM_CRIT("no picked branch (%d) for a final response" " in MODE_ONFAILURE\n", branch); return -1; } if(rewrite_uri(msg, &(t->uac[branch].uri))<0) { LM_WARN("failed to rewrite the r-uri\n"); } set_ruid(msg, &(t->uac[branch].ruid)); if (t->uac[branch].path.len) { if(set_path_vector(msg, &(t->uac[branch].path))<0) { LM_WARN("failed to set the path vector\n"); } } else { reset_path_vector(msg); } setbflagsval(0, t->uac[branch].branch_flags); set_instance(msg, &(t->uac[branch].instance)); return 1; default: LM_ERR("unsupported route_type %d\n", get_route_type()); return -1; } }
/*! * \brief Necessary logic to forward request to strict routers * \param _m SIP message * \param _hdr SIP header field * \param _r Route & Record-Route header field body * \return 0 on success, negative on an error */ static inline int handle_sr(struct sip_msg* _m, struct hdr_field* _hdr, rr_t* _r) { str uri; char* rem_off; int rem_len; /* Next hop is strict router, save R-URI here */ if (save_ruri(_m) < 0) { LM_ERR("failed to save Request-URI\n"); return -1; } /* Put the first Route in Request-URI */ uri = _r->nameaddr.uri; if(get_maddr_uri(&uri, 0)!=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 -2; } if (!_r->next) { rem_off = _hdr->name.s; rem_len = _hdr->len; } else { rem_off = _hdr->body.s; rem_len = _r->next->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 -9; } return 0; }
/*! \brief * Lookup contact in the database and rewrite Request-URI * \return: -1 : not found * -2 : found but method not allowed * -3 : error */ int lookup(struct sip_msg* _m, udomain_t* _d) { impurecord_t* r; str aor, uri; ucontact_t* ptr; int res; int ret; str path_dst; flag_t old_bflags; int i = 0; if (_m->new_uri.s) uri = _m->new_uri; else uri = _m->first_line.u.request.uri; if (extract_aor(&uri, &aor) < 0) { LM_ERR("failed to extract address of record\n"); return -3; } get_act_time(); ul.lock_udomain(_d, &aor); res = ul.get_impurecord(_d, &aor, &r); if (res > 0) { LM_DBG("'%.*s' Not found in usrloc\n", aor.len, ZSW(aor.s)); ul.unlock_udomain(_d, &aor); return -1; } ret = -1; while (i < MAX_CONTACTS_PER_IMPU && (ptr = r->newcontacts[i])) { if (VALID_CONTACT(ptr, act_time) && allowed_method(_m, ptr)) { LM_DBG("Found a valid contact [%.*s]\n", ptr->c.len, ptr->c.s); i++; break; } i++; } /* look first for an un-expired and suported contact */ if (ptr == 0) { /* nothing found */ goto done; } ret = 1; if (ptr) { if (rewrite_uri(_m, &ptr->c) < 0) { LM_ERR("unable to rewrite Request-URI\n"); ret = -3; goto done; } /* reset next hop address */ reset_dst_uri(_m); /* If a Path is present, use first path-uri in favour of * received-uri because in that case the last hop towards the uac * has to handle NAT. - agranig */ if (ptr->path.s && ptr->path.len) { if (get_path_dst_uri(&ptr->path, &path_dst) < 0) { LM_ERR("failed to get dst_uri for Path\n"); ret = -3; goto done; } if (set_path_vector(_m, &ptr->path) < 0) { LM_ERR("failed to set path vector\n"); ret = -3; goto done; } if (set_dst_uri(_m, &path_dst) < 0) { LM_ERR("failed to set dst_uri of Path\n"); ret = -3; goto done; } } else if (ptr->received.s && ptr->received.len) { if (set_dst_uri(_m, &ptr->received) < 0) { ret = -3; goto done; } } set_ruri_q(ptr->q); old_bflags = 0; getbflagsval(0, &old_bflags); setbflagsval(0, old_bflags | ptr->cflags); if (ptr->sock) set_force_socket(_m, ptr->sock); ptr = ptr->next; } /* Append branches if enabled */ if (!cfg_get(registrar, registrar_cfg, append_branches)) goto done; //the last i was the first valid contact we found - let's go through the rest of valid contacts and append the branches. while (i < MAX_CONTACTS_PER_IMPU && (ptr = r->newcontacts[i])) { if (VALID_CONTACT(ptr, act_time) && allowed_method(_m, ptr)) { path_dst.len = 0; if (ptr->path.s && ptr->path.len && get_path_dst_uri(&ptr->path, &path_dst) < 0) { LM_ERR("failed to get dst_uri for Path\n"); continue; } /* The same as for the first contact applies for branches * regarding path vs. received. */ if (km_append_branch(_m, &ptr->c, path_dst.len ? &path_dst : &ptr->received, &ptr->path, ptr->q, ptr->cflags, ptr->sock) == -1) { LM_ERR("failed to append a branch\n"); /* Also give a chance to the next branches*/ continue; } } i++; } done: ul.unlock_udomain(_d, &aor); return ret; }
int enum_pv_query_3(struct sip_msg* _msg, char* _sp, char* _suffix, char* _service) { char *user_s; int user_len, i, j, first; char name[MAX_DOMAIN_SIZE]; char uri[MAX_URI_SIZE]; char new_uri[MAX_URI_SIZE]; unsigned int priority, curr_prio; qvalue_t q; struct rdata* head; struct rdata* l; struct naptr_rdata* naptr; str pattern, replacement, result, new_result; str *suffix, *service; char string[MAX_NUM_LEN]; pv_spec_t *sp; pv_value_t pv_val; sp = (pv_spec_t *)_sp; suffix = (str*)_suffix; service = (str*)_service; /* * Get E.164 number from pseudo variable */ if (sp && (pv_get_spec_value(_msg, sp, &pv_val) == 0)) { if (pv_val.flags & PV_VAL_STR) { if (pv_val.rs.len == 0 || pv_val.rs.s == NULL) { LM_DBG("Missing E.164 number\n"); return -1; } } else { LM_DBG("Pseudo variable value is not string\n"); return -1; } } else { LM_DBG("Cannot get pseudo variable value\n"); return -1; } if (is_e164(&(pv_val.rs)) == -1) { LM_ERR("pseudo variable does not contain an E164 number\n"); return -1; } user_s = pv_val.rs.s; user_len = pv_val.rs.len; memcpy(&(string[0]), user_s, user_len); string[user_len] = (char)0; j = 0; for (i = user_len - 1; i > 0; i--) { name[j] = user_s[i]; name[j + 1] = '.'; j = j + 2; } memcpy(name + j, suffix->s, suffix->len + 1); head = get_record(name, T_NAPTR, RES_ONLY_TYPE); if (head == 0) { LM_DBG("No NAPTR record found for %s.\n", name); return -1; } naptr_sort(&head); q = MAX_Q - 10; curr_prio = 0; first = 1; for (l = head; l; l = l->next) { if (l->type != T_NAPTR) continue; /*should never happen*/ naptr = (struct naptr_rdata*)l->rdata; if (naptr == 0) { LM_ERR("Null rdata in DNS response\n"); continue; } LM_DBG("ENUM query on %s: order %u, pref %u, flen %u, flags " "'%.*s', slen %u, services '%.*s', rlen %u, " "regexp '%.*s'\n", name, naptr->order, naptr->pref, naptr->flags_len, (int)(naptr->flags_len), ZSW(naptr->flags), naptr->services_len, (int)(naptr->services_len), ZSW(naptr->services), naptr->regexp_len, (int)(naptr->regexp_len), ZSW(naptr->regexp)); if (sip_match(naptr, service) == 0) continue; if (parse_naptr_regexp(&(naptr->regexp[0]), naptr->regexp_len, &pattern, &replacement) < 0) { LM_ERR("Parsing of NAPTR regexp failed\n"); continue; } result.s = &(uri[0]); result.len = MAX_URI_SIZE; /* Avoid making copies of pattern and replacement */ pattern.s[pattern.len] = (char)0; replacement.s[replacement.len] = (char)0; if (reg_replace(pattern.s, replacement.s, &(string[0]), &result) < 0) { pattern.s[pattern.len] = '!'; replacement.s[replacement.len] = '!'; LM_ERR("Regexp replace failed\n"); continue; } LM_DBG("Resulted in replacement: '%.*s'\n", result.len, ZSW(result.s)); pattern.s[pattern.len] = '!'; replacement.s[replacement.len] = '!'; if (param.len > 0) { if (result.len + param.len > MAX_URI_SIZE - 1) { LM_ERR("URI is too long\n"); continue; } new_result.s = &(new_uri[0]); new_result.len = MAX_URI_SIZE; if (add_uri_param(&result, ¶m, &new_result) == 0) { LM_ERR("Parsing of URI <%.*s> failed\n", result.len, result.s); continue; } if (new_result.len > 0) { result = new_result; } } if (first) { if (rewrite_uri(_msg, &result) == -1) { goto done; } set_ruri_q(q); first = 0; curr_prio = ((naptr->order) << 16) + naptr->pref; } else { priority = ((naptr->order) << 16) + naptr->pref; if (priority > curr_prio) { q = q - 10; curr_prio = priority; } if (append_branch(_msg, &result, 0, 0, q, 0, 0, 0, 0, 0, 0) == -1) { goto done; } } } done: free_rdata_list(head); return first ? -1 : 1; }
/* * Lookup contact in the database and rewrite Request-URI */ int lookup(struct sip_msg* _m, char* _t, char* _s) { urecord_t* r; str uid; ucontact_t* ptr; int res; unsigned int nat; str new_uri; nat = 0; if (get_to_uid(&uid, _m) < 0) return -1; get_act_time(); ul.lock_udomain((udomain_t*)_t); res = ul.get_urecord((udomain_t*)_t, &uid, &r); if (res < 0) { LOG(L_ERR, "lookup(): Error while querying usrloc\n"); ul.unlock_udomain((udomain_t*)_t); return -2; } if (res > 0) { DBG("lookup(): '%.*s' Not found in usrloc\n", uid.len, ZSW(uid.s)); ul.unlock_udomain((udomain_t*)_t); return -3; } ptr = r->contacts; while ((ptr) && !VALID_CONTACT(ptr, act_time)) ptr = ptr->next; if (ptr) { if (ptr->received.s && ptr->received.len) { if (received_to_uri){ if (add_received(&new_uri, &ptr->c, &ptr->received)<0){ LOG(L_ERR, "ERROR: lookup(): out of memory\n"); return -4; } /* replace the msg uri */ if (_m->new_uri.s) pkg_free(_m->new_uri.s); _m->new_uri=new_uri; _m->parsed_uri_ok=0; ruri_mark_new(); goto skip_rewrite_uri; }else if (set_dst_uri(_m, &ptr->received) < 0) { ul.unlock_udomain((udomain_t*)_t); return -4; } } if (rewrite_uri(_m, &ptr->c) < 0) { LOG(L_ERR, "lookup(): Unable to rewrite Request-URI\n"); ul.unlock_udomain((udomain_t*)_t); return -4; } if (ptr->sock) { set_force_socket(_m, ptr->sock); } skip_rewrite_uri: set_ruri_q(ptr->q); nat |= ptr->flags & FL_NAT; ptr = ptr->next; } else { /* All contacts expired */ ul.unlock_udomain((udomain_t*)_t); return -5; } /* Append branches if enabled */ if (!append_branches) goto skip; while(ptr) { if (VALID_CONTACT(ptr, act_time)) { if (received_to_uri && ptr->received.s && ptr->received.len){ if (add_received(&new_uri, &ptr->c, &ptr->received)<0){ LOG(L_ERR, "ERROR: lookup(): branch: out of memory\n"); goto cont; /* try to continue */ } if (append_branch(_m, &new_uri, 0, 0, ptr->q, 0, 0) == -1) { LOG(L_ERR, "lookup(): Error while appending a branch\n"); pkg_free(new_uri.s); if (ser_error==E_TOO_MANY_BRANCHES) goto skip; else goto cont; /* try to continue, maybe we have an oversized contact */ } pkg_free(new_uri.s); /* append_branch doesn't free it */ }else{ if (append_branch(_m, &ptr->c, &ptr->received, 0 /* path */, ptr->q, 0 /* brflags*/, ptr->sock) == -1) { LOG(L_ERR, "lookup(): Error while appending a branch\n"); goto skip; /* Return OK here so the function succeeds */ } } nat |= ptr->flags & FL_NAT; } cont: ptr = ptr->next; } skip: ul.unlock_udomain((udomain_t*)_t); if (nat) setflag(_m, load_nat_flag); return 1; }
int rtjson_init_serial(sip_msg_t *msg, srjson_doc_t *jdoc, sr_xavp_t *iavp) { srjson_t *tj = NULL; srjson_t *nj = NULL; srjson_t *rj = NULL; str val; unsigned int bflags = 0; unsigned int old_bflags = 0; struct socket_info* fsocket = NULL; tj = srjson_GetObjectItem(jdoc, jdoc->root, "routes"); if(tj==NULL || tj->type!=srjson_Array || tj->child==NULL) { LM_ERR("missing or invalid routes field\n"); goto error; } nj = tj->child; clear_branches(); rj = srjson_GetObjectItem(jdoc, nj, "uri"); if(rj!=NULL && rj->type==srjson_String && rj->valuestring!=NULL) { val.s = rj->valuestring; val.len = strlen(val.s); LM_DBG("rewrite r-uri to: [%.*s]\n", val.len, val.s); if (rewrite_uri(msg, &val) < 0) { LM_ERR("unable to rewrite Request-URI\n"); goto error; } } reset_dst_uri(msg); reset_path_vector(msg); reset_instance(msg); reset_ruid(msg); reset_ua(msg); reset_force_socket(msg); msg->reg_id = 0; set_ruri_q(0); rj = srjson_GetObjectItem(jdoc, nj, "dst_uri"); if(rj!=NULL && rj->type==srjson_String && rj->valuestring!=NULL) { val.s = rj->valuestring; val.len = strlen(val.s); LM_DBG("rewrite dst-uri to: [%.*s]\n", val.len, val.s); if (set_dst_uri(msg, &val) < 0) { LM_ERR("unable to set destination uri\n"); goto error; } } rj = srjson_GetObjectItem(jdoc, nj, "path"); if(rj!=NULL && rj->type==srjson_String && rj->valuestring!=NULL) { val.s = rj->valuestring; val.len = strlen(val.s); LM_DBG("rewrite path to: [%.*s]\n", val.len, val.s); if (set_path_vector(msg, &val) < 0) { LM_ERR("unable to set path\n"); goto error; } } rj = srjson_GetObjectItem(jdoc, nj, "socket"); if(rj!=NULL && rj->type==srjson_String && rj->valuestring!=NULL) { val.s = rj->valuestring; val.len = strlen(val.s); LM_DBG("trying to set send socket to: [%.*s]\n", val.len, val.s); fsocket = lookup_local_socket(&val); if(fsocket) { set_force_socket(msg, fsocket); } } rj = srjson_GetObjectItem(jdoc, nj, "branch_flags"); if(rj!=NULL && rj->type==srjson_Number && SRJSON_GET_UINT(rj)!=0) { bflags = SRJSON_GET_UINT(rj); old_bflags = 0; getbflagsval(0, &old_bflags); setbflagsval(0, old_bflags|bflags); } iavp->val.v.i++; return 0; error: return -1; }
/* * Previous hop was a strict router, handle this case */ static inline int after_strict(struct sip_msg* _m, struct sip_uri* _pru, int _route_myself) { int res, rem_len; struct hdr_field* hdr; rr_t* rt, *prev; char* rem_off; str* uri; str avp_cookie; get_avp_cookie_from_uri(&_m->parsed_uri.params, &avp_cookie); if (avp_cookie.len > 0) rr_set_avp_cookies(&avp_cookie, get_direction(_m, &_m->parsed_uri.params)); hdr = _m->route; rt = (rr_t*)hdr->parsed; if (_route_myself == 1) { store_user_in_avps(&(_pru->user)); 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_strict: Cannot remove Route HF\n"); return RR_ERROR; } res = find_next_route(_m, &hdr); if (res < 0) { LOG(L_ERR, "after_strict: Error while searching next route\n"); return RR_ERROR; } if (res > 0) { /* No next route found */ DBG("after_strict: No next URI found\n"); return NOT_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) == -1) { LOG(L_ERR, "after_strict: Error while parsing URI\n"); return RR_ERROR; } } else { uri = &rt->nameaddr.uri; } store_next_route_in_avps(uri); if (is_strict(&(_pru->params))) { DBG("after_strict: 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 (rewrite_uri(_m, uri) < 0) { LOG(L_ERR, "after_strict: Error while rewriting 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)) { LOG(L_ERR, "after_strict: Cannot remove Route HF\n"); return RR_ERROR; } } else { DBG("after_strict: Next hop: '%.*s' is loose router\n", uri->len, ZSW(uri->s)); if (set_dst_uri(_m, uri) < 0) { LOG(L_ERR, "after_strict: Error while setting 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)) { LOG(L_ERR, "after_strict: Can't remove Route HF\n"); return RR_ERROR; } } res = find_rem_target(_m, &hdr, &rt, &prev); if (res < 0) { LOG(L_ERR, "after_strict: Error while looking for last Route URI\n"); return RR_ERROR; } else if (res > 0) { /* No remote target is an error */ return RR_ERROR; } uri = &rt->nameaddr.uri; if (rewrite_uri(_m, uri) < 0) { LOG(L_ERR, "after_strict: Can't 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 */ DBG("after_strict: 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)) { LOG(L_ERR, "after_strict: Can't remove Route HF\n"); return RR_ERROR; } } return RR_DRIVEN; }
int enum_query_2(struct sip_msg* _msg, char* _suffix, char* _service) { char *user_s; int user_len, i, j, first; char name[MAX_DOMAIN_SIZE]; char uri[MAX_URI_SIZE]; char new_uri[MAX_URI_SIZE]; unsigned int priority, curr_prio; qvalue_t q; struct rdata* head; struct rdata* l; struct naptr_rdata* naptr; str pattern, replacement, result, new_result; char string[17]; str *suffix, *service; suffix = (str*)_suffix; service = (str*)_service; if (parse_sip_msg_uri(_msg) < 0) { LOG(L_ERR, "enum_query(): uri parsing failed\n"); return -1; } if (is_e164(&(_msg->parsed_uri.user)) == -1) { LOG(L_ERR, "enum_query(): uri user is not an E164 number\n"); return -1; } user_s = _msg->parsed_uri.user.s; user_len = _msg->parsed_uri.user.len; memcpy(&(string[0]), user_s, user_len); string[user_len] = (char)0; j = 0; for (i = user_len - 1; i > 0; i--) { name[j] = user_s[i]; name[j + 1] = '.'; j = j + 2; } memcpy(name + j, suffix->s, suffix->len + 1); head = get_record(name, T_NAPTR); if (head == 0) { DBG("enum_query(): No NAPTR record found for %s.\n", name); return -1; } naptr_sort(&head); q = MAX_Q - 10; curr_prio = 0; first = 1; for (l = head; l; l = l->next) { if (l->type != T_NAPTR) continue; /*should never happen*/ naptr = (struct naptr_rdata*)l->rdata; if (naptr == 0) { LOG(L_CRIT, "enum_query: BUG: null rdata\n"); continue; } DBG("enum_query(): order %u, pref %u, flen %u, flags '%.*s', slen %u, " "services '%.*s', rlen %u, regexp '%.*s'\n", naptr->order, naptr->pref, naptr->flags_len, (int)(naptr->flags_len), ZSW(naptr->flags), naptr->services_len, (int)(naptr->services_len), ZSW(naptr->services), naptr->regexp_len, (int)(naptr->regexp_len), ZSW(naptr->regexp)); if (sip_match(naptr, service) == 0) continue; if (parse_naptr_regexp(&(naptr->regexp[0]), naptr->regexp_len, &pattern, &replacement) < 0) { LOG(L_ERR, "enum_query(): parsing of NAPTR regexp failed\n"); continue; } result.s = &(uri[0]); result.len = MAX_URI_SIZE; /* Avoid making copies of pattern and replacement */ pattern.s[pattern.len] = (char)0; replacement.s[replacement.len] = (char)0; if (reg_replace(pattern.s, replacement.s, &(string[0]), &result) < 0) { pattern.s[pattern.len] = '!'; replacement.s[replacement.len] = '!'; LOG(L_ERR, "enum_query(): regexp replace failed\n"); continue; } DBG("enum_query(): resulted in replacement: '%.*s'\n", result.len, ZSW(result.s)); pattern.s[pattern.len] = '!'; replacement.s[replacement.len] = '!'; if (param.len > 0) { if (result.len + param.len > MAX_URI_SIZE - 1) { LOG(L_ERR, "ERROR: enum_query(): URI is too long\n"); continue; } new_result.s = &(new_uri[0]); new_result.len = MAX_URI_SIZE; if (add_uri_param(&result, ¶m, &new_result) == 0) { LOG(L_ERR, "ERROR: enum_query(): Parsing of URI failed\n"); continue; } if (new_result.len > 0) { result = new_result; } } if (first) { if (rewrite_uri(_msg, &result) == -1) { goto done; } set_ruri_q(q); first = 0; curr_prio = ((naptr->order) << 16) + naptr->pref; } else { priority = ((naptr->order) << 16) + naptr->pref; if (priority > curr_prio) { q = q - 10; curr_prio = priority; } if (append_branch(_msg, &result, 0, q, 0, 0) == -1) { goto done; } } } done: free_rdata_list(head); return first ? -1 : 1; }
int sbranch_set_ruri(sip_msg_t *msg) { str sv; flag_t old_bflags; branch_t *br; int ret; ret = 0; br = &_pv_sbranch; if(br->len==0) return -1; sv.s = br->uri; sv.len = br->len; if (rewrite_uri(msg, &sv) < 0) { LM_ERR("unable to rewrite Request-URI\n"); ret = -3; goto error; } /* reset next hop address */ reset_dst_uri(msg); if(br->dst_uri_len>0) { sv.s = br->dst_uri; sv.len = br->dst_uri_len; if (set_dst_uri(msg, &sv) < 0) { ret = -3; goto error; } } reset_path_vector(msg); if(br->path_len==0) { sv.s = br->path; sv.len = br->path_len; if(set_path_vector(msg, &sv) < 0) { ret = -4; goto error; } } reset_instance(msg); if (br->instance_len) { sv.s = br->instance; sv.len = br->instance_len; if (set_instance(msg, &sv) < 0) { ret = -5; goto error; } } reset_ruid(msg); if (br->ruid_len) { sv.s = br->ruid; sv.len = br->ruid_len; if (set_ruid(msg, &sv) < 0) { ret = -6; goto error; } } reset_ua(msg); if (br->location_ua_len) { sv.s = br->location_ua; sv.len = br->location_ua_len; if (set_ua(msg, &sv) < 0) { ret = -7; goto error; } } if (br->force_send_socket) set_force_socket(msg, br->force_send_socket); msg->reg_id = br->reg_id; set_ruri_q(br->q); old_bflags = 0; getbflagsval(0, &old_bflags); setbflagsval(0, old_bflags|br->flags); return 0; error: return ret; }
/* * Adds to request a new destination set that includes all highest * priority class contacts in contacts_avp. Request URI is rewritten with * first contact and the remaining contacts (if any) are added as branches. * Removes used contacts from contacts_avp. Returns 1, if contacts_avp * was not empty and a destination set was successfully added. Returns -2, * if contacts_avp was empty and thus there was nothing to do. * Returns -1 in case of an error. */ int t_next_contacts(struct sip_msg* msg, char* key, char* value) { struct usr_avp *avp, *prev; int_str val; str uri, dst, path; struct socket_info *sock; unsigned int flags; struct search_state st; /* Check if contacts_avp has been defined */ if (contacts_avp.n == 0) { LM_ERR("feature has been disabled - " "to enable define contacts_avp module parameter"); return -1; } /* Load Request-URI and branches */ /* Find first contacts_avp value */ avp = search_first_avp(contacts_avp_type, contacts_avp, &val, &st); if (!avp) { LM_DBG("no AVPs - we are done!\n"); return -2; } LM_DBG("next contact is <%.*s>\n", STR_FMT(&val.s)); if (decode_branch_info(val.s.s, &uri, &dst, &path, &sock, &flags) == 0) { LM_ERR("decoding of branch info <%.*s> failed\n", STR_FMT(&val.s)); destroy_avp(avp); return -1; } /* Rewrite Request-URI */ rewrite_uri(msg, &uri); if (dst.s && dst.len) set_dst_uri(msg, &dst); else reset_dst_uri(msg); if (path.s && path.len) set_path_vector(msg, &path); else reset_path_vector(msg); set_force_socket(msg, sock); setbflagsval(0, flags); if (avp->flags & Q_FLAG) { destroy_avp(avp); return 1; } /* Append branches until out of branches or Q_FLAG is set */ prev = avp; while ((avp = search_next_avp(&st, &val))) { destroy_avp(prev); LM_DBG("next contact is <%.*s>\n", STR_FMT(&val.s)); if (decode_branch_info(val.s.s, &uri, &dst, &path, &sock, &flags) == 0) { LM_ERR("decoding of branch info <%.*s> failed\n", STR_FMT(&val.s)); destroy_avp(avp); return -1; } if (append_branch(msg, &uri, &dst, &path, 0, flags, sock) != 1) { LM_ERR("appending branch failed\n"); destroy_avp(avp); return -1; } if (avp->flags & Q_FLAG) { destroy_avp(avp); return 1; } prev = avp; } destroy_avp(prev); return 1; }
/* * Lookup contact in the database and rewrite Request-URI, * and filter them by aor */ int lookup2(struct sip_msg* msg, char* table, char* p2) { urecord_t* r; str uid; ucontact_t* ptr; int res; unsigned int nat; str new_uri, aor; fparam_t* fp; nat = 0; fp = (fparam_t*)p2; if (get_str_fparam(&aor, msg, (fparam_t*)p2) != 0) { ERR("Unable to get the AOR value\n"); return -1; } if (get_to_uid(&uid, msg) < 0) return -1; get_act_time(); ul.lock_udomain((udomain_t*)table); res = ul.get_urecord((udomain_t*)table, &uid, &r); if (res < 0) { ERR("Error while querying usrloc\n"); ul.unlock_udomain((udomain_t*)table); return -2; } if (res > 0) { DBG("'%.*s' Not found in usrloc\n", uid.len, ZSW(uid.s)); ul.unlock_udomain((udomain_t*)table); return -3; } ptr = r->contacts; while (ptr && (!VALID_CONTACT(ptr, act_time) || !VALID_AOR(ptr, aor))) ptr = ptr->next; if (ptr) { if (ptr->received.s && ptr->received.len) { if (received_to_uri){ if (add_received(&new_uri, &ptr->c, &ptr->received) < 0) { ERR("Out of memory\n"); return -4; } /* replace the msg uri */ if (msg->new_uri.s) pkg_free(msg->new_uri.s); msg->new_uri = new_uri; msg->parsed_uri_ok = 0; ruri_mark_new(); goto skip_rewrite_uri; } else if (set_dst_uri(msg, &ptr->received) < 0) { ul.unlock_udomain((udomain_t*)table); return -4; } } if (rewrite_uri(msg, &ptr->c) < 0) { ERR("Unable to rewrite Request-URI\n"); ul.unlock_udomain((udomain_t*)table); return -4; } if (ptr->sock) { set_force_socket(msg, ptr->sock); } skip_rewrite_uri: set_ruri_q(ptr->q); nat |= ptr->flags & FL_NAT; ptr = ptr->next; } else { /* All contacts expired */ ul.unlock_udomain((udomain_t*)table); return -5; } /* Append branches if enabled */ if (!append_branches) goto skip; while(ptr) { if (VALID_CONTACT(ptr, act_time) && VALID_AOR(ptr, aor)) { if (received_to_uri && ptr->received.s && ptr->received.len) { if (add_received(&new_uri, &ptr->c, &ptr->received) < 0) { ERR("branch: out of memory\n"); goto cont; /* try to continue */ } if (append_branch(msg, &new_uri, 0, 0, ptr->q, 0, 0) == -1) { ERR("Error while appending a branch\n"); pkg_free(new_uri.s); if (ser_error == E_TOO_MANY_BRANCHES) goto skip; else goto cont; /* try to continue, maybe we have an oversized contact */ } pkg_free(new_uri.s); /* append_branch doesn't free it */ } else { if (append_branch(msg, &ptr->c, &ptr->received, 0 /* path */, ptr->q, 0, ptr->sock) == -1) { ERR("Error while appending a branch\n"); goto skip; /* Return OK here so the function succeeds */ } } nat |= ptr->flags & FL_NAT; } cont: ptr = ptr->next; } skip: ul.unlock_udomain((udomain_t*)table); if (nat) setflag(msg, load_nat_flag); return 1; }
/*! \brief * Lookup contacts in the database for all branches, including R-URI * \return: -1 : not found * -2 : found but method not allowed (for r-uri) * -3 : error */ int lookup_branches(sip_msg_t *msg, udomain_t *d) { unsigned int nr_branches_start; unsigned int i; int ret; int found; str new_uri; str ruri_b_uri = {0}; str ruri_b_dst_uri = {0}; str ruri_b_path = {0}; int ruri_b_q = Q_UNSPECIFIED; struct socket_info *ruri_b_socket = 0; flag_t ruri_b_flags = 0; str ruri_b_instance = {0}; unsigned int ruri_b_reg_id = 0; str ruri_b_ruid = {0}; str ruri_b_ua = {0}; branch_t *crt = NULL; ret = 1; found = 0; nr_branches_start = nr_branches; /* first lookup the r-uri */ ret = lookup(msg, d, NULL); /* if no other branches -- all done */ if(nr_branches_start==0) return ret; if(ret>0) found = 1; /* backup r-uri branch */ ruri_b_uri = msg->new_uri; ruri_b_dst_uri = msg->dst_uri; ruri_b_path = msg->path_vec; ruri_b_q = get_ruri_q(); ruri_b_socket = msg->force_send_socket; getbflagsval(0, &ruri_b_flags); ruri_b_instance = msg->instance; ruri_b_reg_id = msg->reg_id; ruri_b_ruid = msg->ruid; ruri_b_ua = msg->location_ua; reset_ruri_branch(msg); /* set new uri buf to null, otherwise is freed or overwritten by * rewrite_uri() during branch lookup */ msg->new_uri.len=0; msg->new_uri.s=0; msg->parsed_uri_ok=0; for(i=0; i<nr_branches_start; i++) { crt = get_sip_branch(i); /* it has to be a clean branch to do lookup for it */ if(crt->len <= 0 || crt->dst_uri_len > 0 || crt->path_len > 0 || crt->force_send_socket!=NULL || crt->flags !=0) continue; /* set the new uri from branch and lookup */ new_uri.s = crt->uri; new_uri.len = crt->len; if (rewrite_uri(msg, &new_uri) < 0) { LM_ERR("unable to rewrite Request-URI for branch %u\n", i); ret = -3; goto done; } ret = lookup(msg, d, NULL); if(ret>0) { /* move r-uri branch attributes to crt branch */ found = 1; if (unlikely(msg->new_uri.len > MAX_URI_SIZE - 1)) { LM_ERR("too long uri: %.*s\n", msg->new_uri.len, msg->new_uri.s); ret = -3; goto done; } /* copy the dst_uri */ if (msg->dst_uri.len>0 && msg->dst_uri.s!=NULL) { if (unlikely(msg->dst_uri.len > MAX_URI_SIZE - 1)) { LM_ERR("too long dst_uri: %.*s\n", msg->dst_uri.len, msg->dst_uri.s); ret = -3; goto done; } memcpy(crt->dst_uri, msg->dst_uri.s, msg->dst_uri.len); crt->dst_uri[msg->dst_uri.len] = 0; crt->dst_uri_len = msg->dst_uri.len; } /* copy the path string */ if (unlikely(msg->path_vec.len>0 && msg->path_vec.s!=NULL)) { if (unlikely(msg->path_vec.len > MAX_PATH_SIZE - 1)) { LM_ERR("too long path: %.*s\n", msg->path_vec.len, msg->path_vec.s); ret = -3; goto done; } memcpy(crt->path, msg->path_vec.s, msg->path_vec.len); crt->path[msg->path_vec.len] = 0; crt->path_len = msg->path_vec.len; } /* copy the ruri */ memcpy(crt->uri, msg->new_uri.s, msg->new_uri.len); crt->uri[msg->new_uri.len] = 0; crt->len = msg->new_uri.len; crt->q = get_ruri_q(); crt->force_send_socket = msg->force_send_socket; getbflagsval(0, &crt->flags); } reset_ruri_branch(msg); } done: reset_ruri_branch(msg); /* new uri could be set to allocated buffer by branch lookup */ if(msg->new_uri.s!=NULL) pkg_free(msg->new_uri.s); msg->new_uri = ruri_b_uri; ruri_mark_new(); msg->parsed_uri_ok = 0; msg->dst_uri = ruri_b_dst_uri; msg->path_vec = ruri_b_path; set_ruri_q(ruri_b_q); set_force_socket(msg, ruri_b_socket); setbflagsval(0, ruri_b_flags); msg->instance = ruri_b_instance; msg->reg_id = ruri_b_reg_id; msg->ruid = ruri_b_ruid; msg->location_ua = ruri_b_ua; return (found)?1:ret; }
/* * Makes enum query on name. On success, rewrites user part and * replaces Request-URI. */ int do_query(struct sip_msg* _msg, char *user, char *name, str *service) { char uri[MAX_URI_SIZE]; char new_uri[MAX_URI_SIZE]; unsigned int priority, curr_prio, first; qvalue_t q; struct rdata* head; struct rdata* l; struct naptr_rdata* naptr; str pattern, replacement, result, new_result; head = get_record(name, T_NAPTR, RES_ONLY_TYPE); if (head == 0) { LM_DBG("No NAPTR record found for %s.\n", name); return -1; } naptr_sort(&head); q = MAX_Q - 10; curr_prio = 0; first = 1; for (l = head; l; l = l->next) { if (l->type != T_NAPTR) continue; /*should never happen*/ naptr = (struct naptr_rdata*)l->rdata; if (naptr == 0) { LM_ERR("Null rdata in DNS response\n"); continue; } LM_DBG("ENUM query on %s: order %u, pref %u, flen %u, flags '%.*s', " "slen %u, services '%.*s', rlen %u, regexp '%.*s'\n", name, naptr->order, naptr->pref, naptr->flags_len, (int)(naptr->flags_len), ZSW(naptr->flags), naptr->services_len, (int)(naptr->services_len), ZSW(naptr->services), naptr->regexp_len, (int)(naptr->regexp_len), ZSW(naptr->regexp)); if (sip_match(naptr, service) == 0) continue; if (parse_naptr_regexp(&(naptr->regexp[0]), naptr->regexp_len, &pattern, &replacement) < 0) { LM_ERR("Parsing of NAPTR regexp failed\n"); continue; } result.s = &(uri[0]); result.len = MAX_URI_SIZE; /* Avoid making copies of pattern and replacement */ pattern.s[pattern.len] = (char)0; replacement.s[replacement.len] = (char)0; if (reg_replace(pattern.s, replacement.s, user, &result) < 0) { pattern.s[pattern.len] = '!'; replacement.s[replacement.len] = '!'; LM_ERR("Regexp replace failed\n"); continue; } LM_DBG("Resulted in replacement: '%.*s'\n", result.len, ZSW(result.s)); pattern.s[pattern.len] = '!'; replacement.s[replacement.len] = '!'; if (param.len > 0) { if (result.len + param.len > MAX_URI_SIZE - 1) { LM_ERR("URI is too long\n"); continue; } new_result.s = &(new_uri[0]); new_result.len = MAX_URI_SIZE; if (add_uri_param(&result, ¶m, &new_result) == 0) { LM_ERR("Parsing of URI <%.*s> failed\n", result.len, result.s); continue; } if (new_result.len > 0) { result = new_result; } } if (first) { if (rewrite_uri(_msg, &result) == -1) { goto done; } set_ruri_q(q); first = 0; curr_prio = ((naptr->order) << 16) + naptr->pref; } else { priority = ((naptr->order) << 16) + naptr->pref; if (priority > curr_prio) { q = q - 10; curr_prio = priority; } if (append_branch(_msg, &result, 0, 0, q, 0, 0, 0, 0, 0, 0) == -1) { goto done; } } } done: free_rdata_list(head); return first ? -1 : 1; }
/*! \brief * Lookup contact in the database and rewrite Request-URI * \return: -1 : not found * -2 : found but method not allowed * -3 : error */ int lookup(struct sip_msg* _m, udomain_t* _d, str* _uri) { urecord_t* r; str aor, uri; sip_uri_t puri; ucontact_t* ptr = 0; int res; int ret; str path_dst; flag_t old_bflags; int i; str inst = {0}; unsigned int ahash = 0; sr_xavp_t *xavp=NULL; sr_xavp_t *list=NULL; str xname = {"ruid", 4}; sr_xval_t xval; ret = -1; if (_m->new_uri.s) uri = _m->new_uri; else uri = _m->first_line.u.request.uri; if (extract_aor((_uri)?_uri:&uri, &aor, &puri) < 0) { LM_ERR("failed to extract address of record\n"); return -3; } /* check if gruu */ if(puri.gr.s!=NULL) { if(puri.gr_val.len>0) { /* pub-gruu */ inst = puri.gr_val; LM_DBG("looking up pub gruu [%.*s]\n", inst.len, inst.s); } else { /* temp-gruu */ ahash = 0; inst = puri.user; for(i=inst.len-1; i>=0; i--) { if(inst.s[i]==REG_GRUU_SEP) break; ahash <<= 4; if(inst.s[i] >='0' && inst.s[i] <='9') ahash+=inst.s[i] -'0'; else if (inst.s[i] >='a' && inst.s[i] <='f') ahash+=inst.s[i] -'a'+10; else if (inst.s[i] >='A' && inst.s[i] <='F') ahash+=inst.s[i] -'A'+10; else { LM_ERR("failed to extract temp gruu - invalid hash\n"); return -3; } } if(i<0) { LM_ERR("failed to extract temp gruu - invalid format\n"); return -3; } inst.len = i; LM_DBG("looking up temp gruu [%u / %.*s]\n", ahash, inst.len, inst.s); } } get_act_time(); if(puri.gr.s==NULL || puri.gr_val.len>0) { /* aor or pub-gruu lookup */ ul.lock_udomain(_d, &aor); res = ul.get_urecord(_d, &aor, &r); if (res > 0) { LM_DBG("'%.*s' Not found in usrloc\n", aor.len, ZSW(aor.s)); ul.unlock_udomain(_d, &aor); return -1; } ptr = r->contacts; ret = -1; /* look first for an un-expired and suported contact */ while (ptr) { if(VALID_CONTACT(ptr,act_time)) { if(allowed_method(_m,ptr)) { /* match on instance, if pub-gruu */ if(inst.len>0) { if(reg_cmp_instances(&inst, &ptr->instance)==0) { /* pub-gruu - found by instance */ LM_DBG("contact for [%.*s] found by pub gruu [%.*s]\n", aor.len, ZSW(aor.s), inst.len, inst.s); break; } } else { /* no-gruu - found by address */ LM_DBG("contact for [%.*s] found by address\n", aor.len, ZSW(aor.s)); break; } } else { LM_DBG("contact for [%.*s] cannot handle the SIP method\n", aor.len, ZSW(aor.s)); ret = -2; } } ptr = ptr->next; } if (ptr==0) { /* nothing found */ LM_DBG("'%.*s' has no valid contact in usrloc\n", aor.len, ZSW(aor.s)); goto done; } } else { /* temp-gruu lookup */ res = ul.get_urecord_by_ruid(_d, ahash, &inst, &r, &ptr); if(res<0) { LM_DBG("temp gruu '%.*s' not found in usrloc\n", aor.len, ZSW(aor.s)); return -1; } aor = *ptr->aor; /* test if un-expired and suported contact */ if( (ptr) && !(VALID_CONTACT(ptr,act_time) && (ret=-2) && allowed_method(_m,ptr))) goto done; LM_DBG("contact for [%.*s] found by temp gruu [%.*s / %u]\n", aor.len, ZSW(aor.s), inst.len, inst.s, ahash); } ret = 1; if (ptr) { if (rewrite_uri(_m, &ptr->c) < 0) { LM_ERR("unable to rewrite Request-URI\n"); ret = -3; goto done; } /* reset next hop address */ reset_dst_uri(_m); /* add xavp with details of the record (ruid, ...) */ if(reg_xavp_rcd.s!=NULL) { list = xavp_get(®_xavp_rcd, NULL); xavp = list; memset(&xval, 0, sizeof(sr_xval_t)); xval.type = SR_XTYPE_STR; xval.v.s = ptr->ruid; xavp_add_value(&xname, &xval, &xavp); if(list==NULL) { /* no reg_xavp_rcd xavp in root list - add it */ xval.type = SR_XTYPE_XAVP; xval.v.xavp = xavp; xavp_add_value(®_xavp_rcd, &xval, NULL); } } /* If a Path is present, use first path-uri in favour of * received-uri because in that case the last hop towards the uac * has to handle NAT. - agranig */ if (ptr->path.s && ptr->path.len) { if (get_path_dst_uri(&ptr->path, &path_dst) < 0) { LM_ERR("failed to get dst_uri for Path\n"); ret = -3; goto done; } if (set_path_vector(_m, &ptr->path) < 0) { LM_ERR("failed to set path vector\n"); ret = -3; goto done; } if (set_dst_uri(_m, &path_dst) < 0) { LM_ERR("failed to set dst_uri of Path\n"); ret = -3; goto done; } } else if (ptr->received.s && ptr->received.len) { if (set_dst_uri(_m, &ptr->received) < 0) { ret = -3; goto done; } } if (ptr->instance.len) { if (set_instance(_m, &(ptr->instance)) < 0) { ret = -3; goto done; } } _m->reg_id = ptr->reg_id; if (ptr->ruid.len) { if (set_ruid(_m, &(ptr->ruid)) < 0) { ret = -3; goto done; } } if (ptr->user_agent.len) { if (set_ua(_m, &(ptr->user_agent)) < 0) { ret = -3; goto done; } } set_ruri_q(ptr->q); old_bflags = 0; getbflagsval(0, &old_bflags); setbflagsval(0, old_bflags|ptr->cflags); if (ptr->sock) set_force_socket(_m, ptr->sock); if(ptr->xavp!=NULL) { xavp = xavp_clone_level_nodata(ptr->xavp); if(xavp_add(xavp, NULL)<0) { ret = -3; goto done; } } ptr = ptr->next; } /* if was gruu, no more branches */ if(inst.len>0) goto done; /* Append branches if enabled */ if (!cfg_get(registrar, registrar_cfg, append_branches)) goto done; for( ; ptr ; ptr = ptr->next ) { if (VALID_CONTACT(ptr, act_time) && allowed_method(_m, ptr)) { path_dst.len = 0; if(ptr->path.s && ptr->path.len && get_path_dst_uri(&ptr->path, &path_dst) < 0) { LM_ERR("failed to get dst_uri for Path\n"); continue; } /* The same as for the first contact applies for branches * regarding path vs. received. */ LM_DBG("instance is %.*s\n", ptr->instance.len, ptr->instance.s); if (append_branch(_m, &ptr->c, path_dst.len?&path_dst:&ptr->received, &ptr->path, ptr->q, ptr->cflags, ptr->sock, ptr->instance.len?&(ptr->instance):0, ptr->instance.len?ptr->reg_id:0, &ptr->ruid, &ptr->user_agent) == -1) { LM_ERR("failed to append a branch\n"); /* Also give a chance to the next branches*/ continue; } if(ptr->xavp!=NULL) { xavp = xavp_clone_level_nodata(ptr->xavp); if(xavp_insert(xavp, nr_branches, NULL)<0) { ret = -3; goto done; } } } } done: ul.release_urecord(r); ul.unlock_udomain(_d, &aor); return ret; }
int sd_lookup(struct sip_msg* _msg, char* _index, char* _str2) { int i; str user_s, uid, did; db_res_t* res = NULL; db_rec_t* rec; /* init */ i = (int)(long)_index; /* Retrieve the owner of the record */ if (get_from_uid(&uid, _msg) < 0) { LOG(L_ERR, "sd_lookup: Unable to get user identity\n"); return -1; } /* Retrieve the called domain id */ if (get_to_did(&did, _msg) < 0) { LOG(L_ERR, "sd_lookup: Destination domain ID not known\n"); return -1; } tables[i].lookup_num->match[0].v.lstr = uid; tables[i].lookup_num->match[1].v.lstr = did; /* Get the called username */ if (parse_sip_msg_uri(_msg) < 0) { LOG(L_ERR, "sd_lookup: Error while parsing Request-URI\n"); goto err_badreq; } tables[i].lookup_num->match[2].v.lstr = _msg->parsed_uri.user; DBG("speeddial: Looking up (uid:%.*s,username:%.*s,did:%.*s)\n", uid.len, uid.s, _msg->parsed_uri.user.len, _msg->parsed_uri.user.s, did.len, did.s); if (db_exec(&res, tables[i].lookup_num) < 0) { ERR("speeddial: Error while executing database command\n"); goto err_server; } if (res == NULL) { DBG("speeddial: No SIP URI found for speeddial (num:%.*s, uid:%.*s," " did:%.*s)\n", _msg->parsed_uri.user.len, _msg->parsed_uri.user.s, uid.len, uid.s, did.len, did.s); return -1; } user_s.s = useruri_buf + 4; rec = db_first(res); while(rec) { if (rec->fld[0].flags & DB_NULL) goto skip; strncpy(user_s.s, rec->fld[0].v.lstr.s, rec->fld[0].v.lstr.len); user_s.len = rec->fld[0].v.lstr.len; user_s.s[user_s.len] = '\0'; goto out; skip: rec = db_next(res); } if (rec == NULL) { DBG("speeddial: No usable SIP URI found for (num:%.*s, uid:%.*s," " did:%.*s)\n", _msg->parsed_uri.user.len, _msg->parsed_uri.user.s, uid.len, uid.s, did.len, did.s); db_res_free(res); return -1; } out: /* check 'sip:' */ if(user_s.len<4 || strncmp(user_s.s, "sip:", 4)) { memcpy(useruri_buf, "sip:", 4); user_s.s -= 4; user_s.len += 4; } db_res_free(res); /* set the URI */ DBG("sd_lookup: URI of sd from R-URI [%s]\n", user_s.s); if(rewrite_uri(_msg, &user_s)<0) { LOG(L_ERR, "sd_lookup: Cannot replace the R-URI\n"); goto err_server; } return 1; err_server: if (slb.zreply(_msg, 500, "Server Internal Error") == -1) { LOG(L_ERR, "sd_lookup: Error while sending reply\n"); } return 0; err_badreq: if (slb.zreply(_msg, 400, "Bad Request") == -1) { LOG(L_ERR, "sd_lookup: Error while sending reply\n"); } return 0; }
/* * Lookup contact in the database and rewrite Request-URI */ int lookup(struct sip_msg* _m, char* _t, char* _s) { urecord_t* r; str aor, uri; ucontact_t* ptr; int res; int bflags; if (_m->new_uri.s) uri = _m->new_uri; else uri = _m->first_line.u.request.uri; if (extract_aor(&uri, &aor) < 0) { LOG(L_ERR, "lookup(): Error while extracting address of record\n"); return -1; } get_act_time(); ul.lock_udomain((udomain_t*)_t); res = ul.get_urecord((udomain_t*)_t, &aor, &r); if (res < 0) { LOG(L_ERR, "lookup(): Error while querying usrloc\n"); ul.unlock_udomain((udomain_t*)_t); return -2; } if (res > 0) { DBG("lookup(): '%.*s' Not found in usrloc\n", aor.len, ZSW(aor.s)); ul.unlock_udomain((udomain_t*)_t); return -3; } ptr = r->contacts; while ((ptr) && !VALID_CONTACT(ptr, act_time)) ptr = ptr->next; if (ptr) { if (rewrite_uri(_m, &ptr->c) < 0) { LOG(L_ERR, "lookup(): Unable to rewrite Request-URI\n"); ul.unlock_udomain((udomain_t*)_t); return -4; } if (ptr->received.s && ptr->received.len) { if (set_dst_uri(_m, &ptr->received) < 0) { ul.unlock_udomain((udomain_t*)_t); return -4; } } set_ruri_q(ptr->q); /* for RURI branch, the nat flag goes into msg */ if ( ptr->flags&FL_NAT ) _m->flags |= nat_flag; if (ptr->sock) _m->force_send_socket = ptr->sock; ptr = ptr->next; } else { /* All contacts expired */ ul.unlock_udomain((udomain_t*)_t); return -5; } /* Append branches if enabled */ if (!append_branches) goto skip; for( ; ptr ; ptr = ptr->next ) { if (VALID_CONTACT(ptr, act_time)) { /* for additional branches, the nat flag goes into dset */ bflags = (use_branch_flags && (ptr->flags & FL_NAT))?nat_flag:0; if (append_branch(_m, &ptr->c, &ptr->received, ptr->q, bflags, ptr->sock) == -1) { LOG(L_ERR, "lookup(): Error while appending a branch\n"); /* Return 1 here so the function succeeds even if * appending of a branch failed */ /* Also give a chance to the next branches*/ continue; } if (!use_branch_flags && (ptr->flags & FL_NAT)) _m->flags |= nat_flag; } } skip: ul.unlock_udomain((udomain_t*)_t); return 1; }
int I_scscf_select(struct sip_msg* msg, char* str1, char* str2) { str call_id,scscf_name={0,0}; struct sip_msg *req; int result; str hdr={0,0}; //print_scscf_list(L_ERR); call_id = cscf_get_call_id(msg,0); LOG(L_DBG,"DBG:"M_NAME":I_scscf_select(): <%.*s>\n",call_id.len,call_id.s); if (!call_id.len) return CSCF_RETURN_FALSE; scscf_name = take_scscf_entry(call_id); if (!scscf_name.len){ I_scscf_drop(msg,str1,str2); cscf_reply_transactional(msg,600,MSG_600_FORWARDING_FAILED); return CSCF_RETURN_BREAK; } if (msg->first_line.u.request.method.len==8 && strncasecmp(msg->first_line.u.request.method.s,"REGISTER",8)==0) { /* REGISTER fwding */ if (str1&&str1[0]=='0'){ /* first time */ //LOG(L_CRIT,"rewrite uri\n"); if (rewrite_uri(msg, &(scscf_name)) < 0) { LOG(L_ERR,"ERR:"M_NAME":I_UAR_forward: Unable to Rewrite URI\n"); result = CSCF_RETURN_FALSE; }else result = CSCF_RETURN_TRUE; }else{ /* subsequent */ //LOG(L_CRIT,"append branch\n"); req = msg;//cscf_get_request_from_reply(msg); append_branch(req,scscf_name.s,scscf_name.len,0,0,0,0); result = CSCF_RETURN_TRUE; } }else{ /* Another request */ result = CSCF_RETURN_TRUE; hdr.len = route_hdr_s.len+scscf_name.len+route_hdr_e.len; hdr.s = pkg_malloc(hdr.len); if (!hdr.s){ LOG(L_ERR,"ERR:"M_NAME":Mw_REQUEST_forward: Error allocating %d bytes\n", hdr.len); result = CSCF_RETURN_TRUE; } hdr.len=0; STR_APPEND(hdr,route_hdr_s); STR_APPEND(hdr,scscf_name); STR_APPEND(hdr,route_hdr_e); if (!cscf_add_header_first(msg,&hdr,HDR_ROUTE_T)){ pkg_free(hdr.s); result = CSCF_RETURN_TRUE; } if (msg->dst_uri.s) pkg_free(msg->dst_uri.s); STR_PKG_DUP(msg->dst_uri,scscf_name,"pkg"); } if (scscf_name.s) shm_free(scscf_name.s); return result; out_of_memory: if (scscf_name.s) shm_free(scscf_name.s); return CSCF_RETURN_ERROR; }
int tps_request_received(sip_msg_t *msg, int dialog) { tps_data_t mtsd; tps_data_t stsd; str lkey; str ftag; str nuri; uint32_t direction = TPS_DIR_DOWNSTREAM; int ret; LM_DBG("handling incoming request\n"); if(dialog==0) { /* nothing to do for initial request */ return 0; } memset(&mtsd, 0, sizeof(tps_data_t)); memset(&stsd, 0, sizeof(tps_data_t)); if(tps_pack_message(msg, &mtsd)<0) { LM_ERR("failed to extract and pack the headers\n"); return -1; } ret = tps_dlg_message_update(msg, &mtsd); if(ret<0) { LM_ERR("failed to update on dlg message\n"); return -1; } lkey = msg->callid->body; tps_storage_lock_get(&lkey); if(tps_storage_load_dialog(msg, &mtsd, &stsd)<0) { goto error; } /* detect direction - get from-tag */ if(parse_from_header(msg)<0 || msg->from==NULL) { LM_ERR("failed getting 'from' header!\n"); goto error; } ftag = get_from(msg)->tag_value; if(stsd.a_tag.len!=ftag.len) { direction = TPS_DIR_UPSTREAM; } else { if(memcmp(stsd.a_tag.s, ftag.s, ftag.len)==0) { direction = TPS_DIR_DOWNSTREAM; } else { direction = TPS_DIR_UPSTREAM; } } mtsd.direction = direction; tps_storage_lock_release(&lkey); if(direction == TPS_DIR_UPSTREAM) { nuri = stsd.a_contact; } else { nuri = stsd.b_contact; } if(nuri.len>0) { if(rewrite_uri(msg, &nuri)<0) { LM_ERR("failed to update r-uri\n"); return -1; } } if(tps_reappend_route(msg, &stsd, &stsd.s_rr, (direction==TPS_DIR_UPSTREAM)?0:1)<0) { LM_ERR("failed to reappend s-route\n"); return -1; } if(direction == TPS_DIR_UPSTREAM) { if(tps_reappend_route(msg, &stsd, &stsd.a_rr, 0)<0) { LM_ERR("failed to reappend a-route\n"); return -1; } } else { if(tps_reappend_route(msg, &stsd, &stsd.b_rr, 0)<0) { LM_ERR("failed to reappend b-route\n"); return -1; } } if(dialog!=0) { tps_append_xuuid(msg, &stsd.a_uuid); } return 0; error: tps_storage_lock_release(&lkey); return -1; }
/*! * \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; }
/* * Adds a new parameter to Request URI */ int add_uri_param(struct sip_msg* _msg, char* _param, char* _s2) { str *param, *cur_uri, new_uri; struct sip_uri *parsed_uri; char *at; param = (str*)_param; if (param->len == 0) { return 1; } if (parse_sip_msg_uri(_msg) < 0) { LM_ERR("ruri parsing failed\n"); return -1; } parsed_uri = &(_msg->parsed_uri); /* if current ruri has no headers, pad param at the end */ if (parsed_uri->headers.len == 0) { cur_uri = GET_RURI(_msg); new_uri.len = cur_uri->len + param->len + 1; if (new_uri.len > MAX_URI_SIZE) { LM_ERR("new ruri too long\n"); return -1; } new_uri.s = pkg_malloc(new_uri.len); if (new_uri.s == 0) { LM_ERR("add_uri_param(): Memory allocation failure\n"); return -1; } memcpy(new_uri.s, cur_uri->s, cur_uri->len); *(new_uri.s + cur_uri->len) = ';'; memcpy(new_uri.s + cur_uri->len + 1, param->s, param->len); if (rewrite_uri(_msg, &new_uri ) == 1) { goto ok; } else { goto nok; } } /* otherwise take the long path */ new_uri.len = 4 + (parsed_uri->user.len ? parsed_uri->user.len + 1 : 0) + (parsed_uri->passwd.len ? parsed_uri->passwd.len + 1 : 0) + parsed_uri->host.len + (parsed_uri->port.len ? parsed_uri->port.len + 1 : 0) + parsed_uri->params.len + param->len + 1 + parsed_uri->headers.len + 1; if (new_uri.len > MAX_URI_SIZE) { LM_ERR("new ruri too long\n"); return -1; } new_uri.s = pkg_malloc(new_uri.len); if (new_uri.s == 0) { LM_ERR("no more pkg memory\n"); return -1; } at = new_uri.s; memcpy(at, "sip:", 4); at = at + 4; if (parsed_uri->user.len) { memcpy(at, parsed_uri->user.s, parsed_uri->user.len); if (parsed_uri->passwd.len) { *at = ':'; at = at + 1; memcpy(at, parsed_uri->passwd.s, parsed_uri->passwd.len); at = at + parsed_uri->passwd.len; }; *at = '@'; at = at + 1; } memcpy(at, parsed_uri->host.s, parsed_uri->host.len); at = at + parsed_uri->host.len; if (parsed_uri->port.len) { *at = ':'; at = at + 1; memcpy(at, parsed_uri->port.s, parsed_uri->port.len); at = at + parsed_uri->port.len; } memcpy(at, parsed_uri->params.s, parsed_uri->params.len); at = at + parsed_uri->params.len; *at = ';'; at = at + 1; memcpy(at, param->s, param->len); at = at + param->len; *at = '?'; at = at + 1; memcpy(at, parsed_uri->headers.s, parsed_uri->headers.len); if (rewrite_uri(_msg, &new_uri) == 1) { goto ok; } nok: pkg_free(new_uri.s); return -1; ok: pkg_free(new_uri.s); return 1; }