static int dst_to_msg(struct sip_msg *s_msg, struct sip_msg *d_msg) { /* move RURI */ if (set_ruri( d_msg, GET_RURI(s_msg))<0) { LM_ERR("failed to set new RURI\n"); return -1; } /* move DURI (empty is accepted as reset) */ if (set_dst_uri( d_msg, &s_msg->dst_uri)<0) { LM_ERR("failed to set DST URI\n"); return -1; } /* move PATH (empty is accepted as reset) */ if (set_path_vector( d_msg, & s_msg->path_vec)<0) { LM_ERR("failed to set PATH\n"); return -1; } /* Qval */ set_ruri_q( d_msg, get_ruri_q(s_msg) ); /* BFLAGS */ setb0flags( d_msg, getb0flags(s_msg) ); /* socket info */ d_msg->force_send_socket = s_msg->force_send_socket; return 0; }
/* * Make a private copy of the string and assign it to new_uri */ int set_ruri(struct sip_msg* msg, str* uri) { char* ptr; if (!msg || !uri) { LM_ERR("invalid parameter value\n"); return -1; } if (msg->new_uri.s && (msg->new_uri.len >= uri->len)) { memcpy(msg->new_uri.s, uri->s, uri->len); msg->new_uri.len = uri->len; } else { ptr = (char*)pkg_malloc(uri->len+1); if (!ptr) { LM_ERR("not enough pkg memory (%d)\n",uri->len); return -1; } memcpy(ptr, uri->s, uri->len); if (msg->new_uri.s) pkg_free(msg->new_uri.s); msg->new_uri.s = ptr; msg->new_uri.len = uri->len; } set_ruri_q(msg, Q_UNSPECIFIED); msg->parsed_uri_ok = 0; return 0; }
int reset_ruri_branch(sip_msg_t *msg) { if(msg==NULL) return -1; reset_dst_uri(msg); reset_path_vector(msg); set_ruri_q(Q_UNSPECIFIED); reset_force_socket(msg); setbflagsval(0, 0); reset_instance(msg); msg->reg_id = 0; return 0; }
/** * only reset the pointers after local backup in lookup_branches */ int clear_ruri_branch(sip_msg_t *msg) { if(msg==NULL) return -1; msg->dst_uri.s = 0; msg->dst_uri.len = 0; msg->path_vec.s = 0; msg->path_vec.len = 0; set_ruri_q(Q_UNSPECIFIED); reset_force_socket(msg); setbflagsval(0, 0); msg->instance.len = 0; msg->reg_id = 0; msg->ruid.s = 0; msg->ruid.len = 0; msg->location_ua.s = 0; msg->location_ua.len = 0; return 0; }
/* returns : -1 - error * 0 - ok, but no contact added * n - ok and n contacts added */ static int shmcontact2dset(struct sip_msg *req, struct sip_msg *sh_rpl, long max, pv_elem_t *reason) { static struct sip_msg dup_rpl; static str scontacts[MAX_CONTACTS_PER_REPLY]; static qvalue_t sqvalues[MAX_CONTACTS_PER_REPLY]; struct hdr_field *hdr; struct hdr_field *contact_hdr; contact_t *contacts; str backup_uri; int n,i; int added; int dup; int ret; dup = 0; /* sh_rpl not duplicated */ ret = 0; /* success and no contact added */ contact_hdr = NULL; hdr = NULL; if (sh_rpl==0 || sh_rpl==FAKED_REPLY) return 0; if ( sh_rpl->msg_flags&FL_SHM_CLONE ) { /* duplicate the reply into private memory to be able * to parse it and after words to free the parsed mems */ memcpy( &dup_rpl, sh_rpl, sizeof(struct sip_msg) ); LM_DBG("duplicating shm reply\n"); dup = 1; /* ok -> force the parsing of contact header */ if ( parse_headers( &dup_rpl, HDR_EOH_F, 0)<0 ) { LM_ERR("dup_rpl parse failed\n"); ret = -1; goto restore; } if (dup_rpl.contact==0) { LM_DBG("contact hdr not found in dup_rpl\n"); goto restore; } contact_hdr = dup_rpl.contact; } else { /* parse directly the current copy */ /* force the parsing of contact header */ if ( parse_headers( sh_rpl, HDR_EOH_F, 0)<0 ) { LM_ERR("sh_rpl parse failed\n"); ret = -1; goto restore; } if (sh_rpl->contact==0) { LM_DBG("contact hdr not found in sh_rpl\n"); goto restore; } contact_hdr = sh_rpl->contact; } /* iterate through all contact headers and extract the URIs */ for( n=0,hdr=contact_hdr ; hdr ; hdr=hdr->sibling ) { /* parse the body of contact header */ if (hdr->parsed==0) { if ( parse_contact(hdr)<0 ) { LM_ERR("contact hdr parse failed\n"); ret = -1; goto restore; } } /* we have the contact header and its body parsed -> sort the contacts * based on the q value */ contacts = ((contact_body_t*)hdr->parsed)->contacts; if (contacts==0) { LM_DBG("contact hdr has no contacts\n"); } else { sort_contacts( contacts, scontacts, sqvalues, &n); } /* clean currently added contact */ if (dup) free_contact( (contact_body_t**)(void*)(&hdr->parsed) ); } if (n==0) { LM_DBG("no contacts left after filtering\n"); goto restore; } /* to many branches ? */ if (max!=-1 && n>max) n = max; LM_DBG("%d contacts remaining after filtering and sorting\n",n); added = 0; /* add the sorted contacts as branches in dset and log this! */ for ( i=0 ; i<n ; i++ ) { LM_DBG("adding contact <%.*s>\n", scontacts[i].len, scontacts[i].s); if (i==0) { /* set RURI*/ if ( set_ruri( req, &scontacts[i])==-1 ) { LM_ERR("failed to set new RURI\n"); goto restore; } set_ruri_q(req, sqvalues[i]); } else { if (append_branch(0,&scontacts[i],0,0,sqvalues[i],0,0)<0) { LM_ERR("failed to add contact to dset\n"); continue; } } added++; if (rd_acc_fct!=0 && reason) { /* log the redirect */ backup_uri = req->new_uri; req->new_uri = scontacts[i]; //FIXME rd_acc_fct( req, (char*)reason, acc_db_table, NULL, NULL, NULL, NULL); req->new_uri = backup_uri; } } ret = (added==0)?-1:added; restore: if (dup==1) { /* free current parsed contact header */ if (hdr && hdr->parsed) free_contact( (contact_body_t**)(void*)(&hdr->parsed) ); /* are any new headers found? */ if (dup_rpl.last_header!=sh_rpl->last_header) { /* identify in the new headere list (from dup_rpl) * the sh_rpl->last_header and start remove everything after */ hdr = sh_rpl->last_header; free_hdr_field_lst(hdr->next); hdr->next=0; } } return ret; }
static int ul_contact_event_to_msg(struct sip_msg *req) { static enum ul_attrs { UL_URI, UL_RECEIVED, UL_PATH, UL_QVAL, UL_SOCKET, UL_BFLAGS, UL_ATTR, UL_MAX } ul_attr; /* keep the names of the AVPs aligned with the contact-related events * from USRLOC module !!!! */ static str ul_names[UL_MAX]= {str_init("uri"),str_init("received"), str_init("path"),str_init("qval"), str_init("socket"),str_init("bflags"), str_init("attr") }; static int avp_ids[UL_MAX] = { -1, -1, -1, -1, -1, -1, -1}; int_str vals[UL_MAX]; int proto, port; str host; str path_dst; if (avp_ids[0]==-1) { /* init the avp IDs mapping us on the UL event */ for( ul_attr=0 ; ul_attr<UL_MAX ; ul_attr++ ){ if (parse_avp_spec( &ul_names[ul_attr], &avp_ids[ul_attr])<0) { LM_ERR("failed to init UL AVP %d/%s\n", ul_attr,ul_names[ul_attr].s); avp_ids[0] = -1; return -1; } } } /* fetch the AVP values one by one */ for( ul_attr=0 ; ul_attr<UL_MAX ; ul_attr++ ) { if (search_first_avp(0, avp_ids[ul_attr], &vals[ul_attr], NULL)==NULL){ LM_ERR("cannot find AVP(%d) for event attr %d/%s\n", avp_ids[ul_attr], ul_attr, ul_names[ul_attr].s); return -1; } } /* OK, we have the values, lets inject them into the SIP msg */ LM_DBG("injecting new branch: uri=<%.*s>, received=<%.*s>," "path=<%.*s>, qval=%d, socket=<%.*s>, bflags=%X, attr=<%.*s>\n", vals[UL_URI].s.len, vals[UL_URI].s.s, vals[UL_RECEIVED].s.len, vals[UL_RECEIVED].s.s, vals[UL_PATH].s.len, vals[UL_PATH].s.s, vals[UL_QVAL].n, vals[UL_SOCKET].s.len, vals[UL_SOCKET].s.s, vals[UL_BFLAGS].n, vals[UL_ATTR].s.len, vals[UL_ATTR].s.s); /* contact URI goes as RURI */ if (set_ruri( req, &vals[UL_URI].s)<0) { LM_ERR("failed to set new RURI\n"); return -1; } /* contact PATH goes as path */ if (vals[UL_PATH].s.len) { if (get_path_dst_uri(&vals[UL_PATH].s, &path_dst) < 0) { LM_ERR("failed to get dst_uri for Path\n"); return -1; } if (set_dst_uri( req, &path_dst) < 0) { LM_ERR("failed to set dst_uri of Path\n"); return -1; } if (set_path_vector( req, &vals[UL_PATH].s)<0) { LM_ERR("failed to set PATH\n"); return -1; } } else /* contact RECEIVED goes as DURI */ if (vals[UL_RECEIVED].s.len) { if (set_dst_uri( req, &vals[UL_RECEIVED].s)<0) { LM_ERR("failed to set DST URI\n"); return -1; } } /* contact Qval goes as RURI Qval */ set_ruri_q( req, vals[UL_QVAL].n); /* contact BFLAGS goes as RURI bflags */ setb0flags( req, vals[UL_BFLAGS].n); /* socket info */ if (vals[UL_SOCKET].s.len) { if ( parse_phostport( vals[UL_SOCKET].s.s, vals[UL_SOCKET].s.len, &host.s, &host.len, &port, &proto) < 0) { LM_ERR("failed to parse socket from Event attr <%.*s>\n", vals[UL_SOCKET].s.len, vals[UL_SOCKET].s.s); } else { req->force_send_socket = grep_sock_info( &host, (unsigned short)port, (unsigned short)proto); } } 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; }
/* * 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; }
/* * 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; }
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; }
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; char tostring[17]; struct rdata* head; struct rdata* l; struct naptr_rdata* naptr; str pattern, replacement, result, new_result; str *suffix, *service; char string[17]; pv_spec_t *sp; pv_value_t pv_val; sp = (pv_spec_t *)_sp; suffix = (str*)_suffix; service = (str*)_service; /* * Get R-URI user to tostring */ if (parse_sip_msg_uri(_msg) < 0) { LM_ERR("R-URI parsing failed\n"); return -1; } user_s = _msg->parsed_uri.user.s; user_len = _msg->parsed_uri.user.len; memcpy(&(tostring[0]), user_s, user_len); tostring[user_len] = (char)0; /* * 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); 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, &(tostring[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 (set_ruri(_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) == -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, char* _t, char* _f, char* _s) { unsigned int flags; urecord_t* r; str aor, uri; ucontact_t* ptr,*it; int res; int ret; str path_dst; str flags_s; char* ua = NULL; char* re_end = NULL; int re_len = 0; char tmp; regex_t ua_re; int regexp_flags = 0; regmatch_t ua_match; pv_value_t val; int_str istr; str sip_instance = {0,0},call_id = {0,0}; /* branch index */ int idx; /* temporary branch values*/ int tlen; char *turi; qvalue_t tq; flags = 0; if (_f && _f[0]!=0) { if (fixup_get_svalue( _m, (gparam_p)_f, &flags_s)!=0) { LM_ERR("invalid owner uri parameter"); return -1; } for( res=0 ; res< flags_s.len ; res++ ) { switch (flags_s.s[res]) { case 'm': flags |= REG_LOOKUP_METHODFILTER_FLAG; break; case 'b': flags |= REG_LOOKUP_NOBRANCH_FLAG; break; case 'r': flags |= REG_BRANCH_AOR_LOOKUP_FLAG; break; case 'u': if (flags_s.s[res+1] != '/') { LM_ERR("no regexp after 'u' flag"); break; } res++; if ((re_end = strrchr(flags_s.s+res+1, '/')) == NULL) { LM_ERR("no regexp after 'u' flag"); break; } res++; re_len = re_end-flags_s.s-res; if (re_len == 0) { LM_ERR("empty regexp"); break; } ua = flags_s.s+res; flags |= REG_LOOKUP_UAFILTER_FLAG; LM_DBG("found regexp /%.*s/", re_len, ua); res += re_len; break; case 'i': regexp_flags |= REG_ICASE; break; case 'e': regexp_flags |= REG_EXTENDED; break; default: LM_WARN("unsuported flag %c \n",flags_s.s[res]); } } } if (flags®_BRANCH_AOR_LOOKUP_FLAG) { /* extract all the branches for further usage */ nbranches = 0; while ( (turi=get_branch(nbranches, &tlen, &tq, NULL, NULL, NULL, NULL)) ) { /* copy uri */ branch_uris[nbranches].s = urimem[nbranches]; if (tlen) { memcpy(branch_uris[nbranches].s, turi, tlen); branch_uris[nbranches].len = tlen; } else { *branch_uris[nbranches].s = '\0'; branch_uris[nbranches].len = 0; } nbranches++; } clear_branches(); idx=0; } if (_s) { if (pv_get_spec_value( _m, (pv_spec_p)_s, &val)!=0) { LM_ERR("failed to get PV value\n"); return -1; } if ( (val.flags&PV_VAL_STR)==0 ) { LM_ERR("PV vals is not string\n"); return -1; } uri = val.rs; } else { if (_m->new_uri.s) uri = _m->new_uri; else uri = _m->first_line.u.request.uri; } if (extract_aor(&uri, &aor,&sip_instance,&call_id) < 0) { LM_ERR("failed to extract address of record\n"); return -3; } get_act_time(); ul.lock_udomain((udomain_t*)_t, &aor); res = ul.get_urecord((udomain_t*)_t, &aor, &r); if (res > 0) { LM_DBG("'%.*s' Not found in usrloc\n", aor.len, ZSW(aor.s)); ul.unlock_udomain((udomain_t*)_t, &aor); return -1; } if (flags & REG_LOOKUP_UAFILTER_FLAG) { tmp = *(ua+re_len); *(ua+re_len) = '\0'; if (regcomp(&ua_re, ua, regexp_flags) != 0) { LM_ERR("bad regexp '%s'\n", ua); *(ua+re_len) = tmp; return -1; } *(ua+re_len) = tmp; } ptr = r->contacts; ret = -1; /* look first for an un-expired and suported contact */ search_valid_contact: while ( (ptr) && !(VALID_CONTACT(ptr,act_time) && (ret=-2) && allowed_method(_m,ptr,flags))) ptr = ptr->next; if (ptr==0) { /* nothing found */ LM_DBG("nothing found !\n"); goto done; } ua_re_check( ret = -1; ptr = ptr->next; goto search_valid_contact ); if (sip_instance.len && sip_instance.s) { LM_DBG("ruri has gruu in lookup\n"); /* uri has GRUU */ if (ptr->instance.len-2 != sip_instance.len || memcmp(ptr->instance.s+1,sip_instance.s,sip_instance.len)) { LM_DBG("no match to sip instace - [%.*s] - [%.*s]\n",ptr->instance.len-2,ptr->instance.s+1, sip_instance.len,sip_instance.s); /* not the targeted instance, search some more */ ptr = ptr->next; goto search_valid_contact; } LM_DBG("matched sip instace\n"); } if (call_id.len && call_id.s) { /* decide whether GRUU is expired or not * * first - match call-id */ if (ptr->callid.len != call_id.len || memcmp(ptr->callid.s,call_id.s,call_id.len)) { LM_DBG("no match to call id - [%.*s] - [%.*s]\n",ptr->callid.len,ptr->callid.s, call_id.len,call_id.s); ptr = ptr->next; goto search_valid_contact; } /* matched call-id, check if there are newer contacts with * same sip instace bup newer last_modified */ it = ptr->next; while ( it ) { if (VALID_CONTACT(it,act_time)) { if (it->instance.len-2 == sip_instance.len && sip_instance.s && memcmp(it->instance.s+1,sip_instance.s,sip_instance.len) == 0) if (it->last_modified > ptr->last_modified) { /* same instance id, but newer modified -> expired GRUU, no match at all */ break; } } it=it->next; } if (it != NULL) { ret = -1; goto done; } } LM_DBG("found a complete match\n"); ret = 1; if (ptr) { LM_DBG("setting as ruri <%.*s>\n",ptr->c.len,ptr->c.s); if (set_ruri(_m, &ptr->c) < 0) { LM_ERR("unable to rewrite Request-URI\n"); ret = -3; goto done; } /* 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( _m, ptr->q); setbflag( _m, 0, ptr->cflags); if (ptr->sock) _m->force_send_socket = ptr->sock; /* populate the 'attributes' avp */ if (attr_avp_name != -1) { istr.s = ptr->attr; if (add_avp_last(AVP_VAL_STR, attr_avp_name, istr) != 0) { LM_ERR("Failed to populate attr avp!\n"); } } ptr = ptr->next; } /* Append branches if enabled */ /* If we got to this point and the URI had a ;gr parameter and it was matched * to a contact. No point in branching */ if ( flags®_LOOKUP_NOBRANCH_FLAG || (sip_instance.len && sip_instance.s) ) goto done; LM_DBG("looking for branches\n"); do { for( ; ptr ; ptr = ptr->next ) { if (VALID_CONTACT(ptr, act_time) && allowed_method(_m,ptr,flags)) { 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; } ua_re_check(continue); /* The same as for the first contact applies for branches * regarding path vs. received. */ LM_DBG("setting branch <%.*s>\n",ptr->c.len,ptr->c.s); if (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; } /* populate the 'attributes' avp */ if (attr_avp_name != -1) { istr.s = ptr->attr; if (add_avp_last(AVP_VAL_STR, attr_avp_name, istr) != 0) { LM_ERR("Failed to populate attr avp!\n"); } } } } /* 0 branches condition also filled; idx initially -1*/ if (!(flags®_BRANCH_AOR_LOOKUP_FLAG) || idx == nbranches) goto done; /* relsease old aor lock */ ul.unlock_udomain((udomain_t*)_t, &aor); ul.release_urecord(r, 0); /* idx starts from -1 */ uri = branch_uris[idx]; if (extract_aor(&uri, &aor, NULL, &call_id) < 0) { LM_ERR("failed to extract address of record for branch uri\n"); return -3; } /* release old urecord */ /* get lock on new aor */ LM_DBG("getting contacts from aor [%.*s]" "in branch %d\n", aor.len, aor.s, idx); ul.lock_udomain((udomain_t*)_t, &aor); res = ul.get_urecord((udomain_t*)_t, &aor, &r); if (res > 0) { LM_DBG("'%.*s' Not found in usrloc\n", aor.len, ZSW(aor.s)); goto done; } idx++; ptr = r->contacts; } while (1);
/*! \brief * Adds to request a destination set that includes all highest priority * class contacts in "serial_avp" AVP. If called from a route block, * rewrites the request uri with first contact and adds the remaining * contacts as branches. If called from failure route block, adds all * contacts as brances. Removes added contacts from "serial_avp" AVP. */ int next_branches( struct sip_msg *msg) { struct usr_avp *avp, *prev; int_str val; struct socket_info *sock_info; qvalue_t q; str uri, dst_uri, path; char *p; unsigned int flags; int rval; if (route_type != REQUEST_ROUTE && route_type != FAILURE_ROUTE ) { /* unsupported route type */ LM_ERR("called from unsupported route type %d\n", route_type); goto error; } /* Find first avp */ avp = search_first_avp(0, serial_avp, &val, 0); if (!avp) { LM_DBG("no AVPs -- we are done!\n"); goto error; } if (!val.s.s) { LM_ERR("invalid avp value\n"); goto error; } /* *sock_info, flags, q, uri, 0, dst_uri, 0, path, 0,... */ p = val.s.s; sock_info = (struct socket_info*) *((long*) p); p += sizeof(long); flags = (unsigned int) *((long*) p); p += sizeof(long); q = (unsigned int) *((long*) p); p += sizeof(long); uri.s = p; uri.len = strlen(p); p += uri.len + 1; dst_uri.s = p; dst_uri.len = strlen(p); p += dst_uri.len + 1; path.s = p; path.len = strlen(p); /* Set Request-URI */ if ( set_ruri(msg, &uri) == -1 || set_dst_uri(msg, &dst_uri) == -1 || set_path_vector(msg, &path) == -1 ) goto error1; msg->force_send_socket = sock_info; set_ruri_q( q ); setb0flags( flags ); LM_DBG("Msg information <%.*s,%.*s,%.*s,%d,%u> (avp flag=%u)\n", uri.len, uri.s, dst_uri.len, dst_uri.s, path.len, path.s, q, flags, avp->flags); if (avp->flags & Q_FLAG) { destroy_avp(avp); goto done; } prev = avp; avp = search_next_avp(prev, &val); destroy_avp(prev); /* Append branches until out of branches or Q_FLAG is set */ while (avp != NULL) { if (!val.s.s) { LM_ERR("invalid avp value\n"); continue; } p = val.s.s; sock_info = (struct socket_info*) *((long*) p); p += sizeof(long); flags = (unsigned int) *((long*) p); p += sizeof(long); q = (unsigned int) *((long*) p); p += sizeof(long); uri.s = p; uri.len = strlen(p); p += strlen(p) + 1; dst_uri.s = p; dst_uri.len = strlen(p); p += strlen(p) + 1; path.s = p; path.len = strlen(p); LM_DBG("Branch information <%.*s,%.*s,%.*s,%d,%u> (avp flag=%u)\n", uri.len, uri.s, dst_uri.len, dst_uri.s, path.len, path.s, q, flags, avp->flags); rval = append_branch(msg, &uri, &dst_uri, &path, q, flags, sock_info); if (rval == -1) { LM_ERR("append_branch failed\n"); goto error1; } if (avp->flags & Q_FLAG) { destroy_avp(avp); goto done; } prev = avp; avp = search_next_avp(prev, &val); destroy_avp(prev); } return 2; done: return (search_next_avp(avp, NULL)==NULL)?2:1; error1: destroy_avp(avp); error: return -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; }
/*! \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; }
/*! \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, char* _t, char* _f, char* _s) { unsigned int flags; urecord_t* r; str aor, uri; ucontact_t* ptr,*it; int res; int ret; str path_dst; str flags_s; pv_value_t val; int_str istr; str sip_instance = {0,0},call_id = {0,0}; flags = 0; if (_f && _f[0]!=0) { if (fixup_get_svalue( _m, (gparam_p)_f, &flags_s)!=0) { LM_ERR("invalid owner uri parameter"); return -1; } for( res=0 ; res< flags_s.len ; res++ ) { switch (flags_s.s[res]) { case 'm': flags |= REG_LOOKUP_METHODFILTER_FLAG; break; case 'b': flags |= REG_LOOKUP_NOBRANCH_FLAG; break; default: LM_WARN("unsuported flag %c \n",flags_s.s[res]); } } } if (_s) { if (pv_get_spec_value( _m, (pv_spec_p)_s, &val)!=0) { LM_ERR("failed to get PV value\n"); return -1; } if ( (val.flags&PV_VAL_STR)==0 ) { LM_ERR("PV vals is not string\n"); return -1; } uri = val.rs; } else { if (_m->new_uri.s) uri = _m->new_uri; else uri = _m->first_line.u.request.uri; } if (extract_aor(&uri, &aor,&sip_instance,&call_id) < 0) { LM_ERR("failed to extract address of record\n"); return -3; } get_act_time(); ul.lock_udomain((udomain_t*)_t, &aor); res = ul.get_urecord((udomain_t*)_t, &aor, &r); if (res > 0) { LM_DBG("'%.*s' Not found in usrloc\n", aor.len, ZSW(aor.s)); ul.unlock_udomain((udomain_t*)_t, &aor); return -1; } ptr = r->contacts; ret = -1; /* look first for an un-expired and suported contact */ search_valid_contact: while ( (ptr) && !(VALID_CONTACT(ptr,act_time) && (ret=-2) && allowed_method(_m,ptr,flags))) ptr = ptr->next; if (ptr==0) { /* nothing found */ LM_DBG("nothing found !\n"); goto done; } if (sip_instance.len && sip_instance.s) { LM_DBG("ruri has gruu in lookup\n"); /* uri has GRUU */ if (ptr->instance.len-2 != sip_instance.len || memcmp(ptr->instance.s+1,sip_instance.s,sip_instance.len)) { LM_DBG("no match to sip instace - [%.*s] - [%.*s]\n",ptr->instance.len-2,ptr->instance.s+1, sip_instance.len,sip_instance.s); /* not the targeted instance, search some more */ ptr = ptr->next; goto search_valid_contact; } LM_DBG("matched sip instace\n"); } if (call_id.len && call_id.s) { /* decide whether GRUU is expired or not * * first - match call-id */ if (ptr->callid.len != call_id.len || memcmp(ptr->callid.s,call_id.s,call_id.len)) { LM_DBG("no match to call id - [%.*s] - [%.*s]\n",ptr->callid.len,ptr->callid.s, call_id.len,call_id.s); ptr = ptr->next; goto search_valid_contact; } /* matched call-id, check if there are newer contacts with * same sip instace bup newer last_modified */ it = ptr->next; while ( it ) { if (VALID_CONTACT(it,act_time)) { if (it->instance.len-2 == sip_instance.len && memcmp(it->instance.s+1,sip_instance.s,sip_instance.len) == 0) if (it->last_modified > ptr->last_modified) { /* same instance id, but newer modified -> expired GRUU, no match at all */ break; } } it=it->next; } if (it != NULL) { ret = -1; goto done; } } LM_DBG("found a complete match\n"); ret = 1; if (ptr) { LM_DBG("setting as ruri <%.*s>\n",ptr->c.len,ptr->c.s); if (set_ruri(_m, &ptr->c) < 0) { LM_ERR("unable to rewrite Request-URI\n"); ret = -3; goto done; } /* 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); setbflag( 0, ptr->cflags); if (ptr->sock) _m->force_send_socket = ptr->sock; /* populate the 'attributes' avp */ if (attr_avp_name != -1) { istr.s = ptr->attr; if (add_avp_last(AVP_VAL_STR, attr_avp_name, istr) != 0) { LM_ERR("Failed to populate attr avp!\n"); } } ptr = ptr->next; } /* Append branches if enabled */ /* If we got to this point and the URI had a ;gr parameter and it was matched * to a contact. No point in branching */ if ( flags®_LOOKUP_NOBRANCH_FLAG || (sip_instance.len && sip_instance.s) ) goto done; LM_DBG("looking for branches\n"); for( ; ptr ; ptr = ptr->next ) { if (VALID_CONTACT(ptr, act_time) && allowed_method(_m,ptr,flags)) { 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("setting branch <%.*s>\n",ptr->c.len,ptr->c.s); if (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; } /* populate the 'attributes' avp */ if (attr_avp_name != -1) { istr.s = ptr->attr; if (add_avp_last(AVP_VAL_STR, attr_avp_name, istr) != 0) { LM_ERR("Failed to populate attr avp!\n"); } } } } done: ul.release_urecord(r); ul.unlock_udomain((udomain_t*)_t, &aor); return ret; }
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; }
/* ret= 0! if action -> end of list(e.g DROP), > 0 to continue processing next actions and <0 on error */ int do_action(struct action* a, struct sip_msg* msg) { int ret; int v; int sec,usec; union sockaddr_union* to; struct proxy_l* p; char* tmp; char *new_uri, *end, *crt; int len,i; int user = 0; int expires = 0; str vals[5]; str result; struct sip_uri uri, next_hop; struct sip_uri *u; unsigned short port; int cmatch; struct action *aitem; struct action *adefault; pv_spec_t *spec; pv_elem_p model; pv_value_t val; pv_elem_t *pve; str name_s; struct timeval start; int end_time; action_elem_t *route_params_bak; int route_params_number_bak; /* reset the value of error to E_UNSPEC so avoid unknowledgable functions to return with error (status<0) and not setting it leaving there previous error; cache the previous value though for functions which want to process it */ prev_ser_error=ser_error; ser_error=E_UNSPEC; start_expire_timer(start,execmsgthreshold); ret=E_BUG; switch ((unsigned char)a->type){ case DROP_T: script_trace("core", "drop", msg, a->line) ; action_flags |= ACT_FL_DROP; case EXIT_T: script_trace("core", "exit", msg, a->line) ; ret=0; action_flags |= ACT_FL_EXIT; break; case RETURN_T: script_trace("core", "return", msg, a->line) ; if (a->elem[0].type == SCRIPTVAR_ST) { spec = (pv_spec_t*)a->elem[0].u.data; if(pv_get_spec_value(msg, spec, &val)!=0 || (val.flags&PV_VAL_NULL)) { ret=-1; } else { if(!(val.flags&PV_VAL_INT)) ret = 1; else ret = val.ri; } pv_value_destroy(&val); } else { ret=a->elem[0].u.number; } action_flags |= ACT_FL_RETURN; break; case FORWARD_T: script_trace("core", "forward", msg, a->line) ; if (a->elem[0].type==NOSUBTYPE){ /* parse uri and build a proxy */ if (msg->dst_uri.len) { ret = parse_uri(msg->dst_uri.s, msg->dst_uri.len, &next_hop); u = &next_hop; } else { ret = parse_sip_msg_uri(msg); u = &msg->parsed_uri; } if (ret<0) { LM_ERR("forward: bad_uri dropping packet\n"); break; } /* create a temporary proxy*/ p=mk_proxy(u->maddr_val.len?&u->maddr_val:&u->host, u->port_no, u->proto, (u->type==SIPS_URI_T)?1:0 ); if (p==0){ LM_ERR("bad host name in uri, dropping packet\n"); ret=E_BAD_ADDRESS; goto error_fwd_uri; } ret=forward_request(msg, p); free_proxy(p); /* frees only p content, not p itself */ pkg_free(p); if (ret==0) ret=1; }else if ((a->elem[0].type==PROXY_ST)) { ret=forward_request(msg,(struct proxy_l*)a->elem[0].u.data); if (ret==0) ret=1; }else{ LM_ALERT("BUG in forward() types %d, %d\n", a->elem[0].type, a->elem[1].type); ret=E_BUG; } break; case SEND_T: script_trace("core", "send", msg, a->line) ; if (a->elem[0].type!= PROXY_ST){ LM_ALERT("BUG in send() type %d\n", a->elem[0].type); ret=E_BUG; break; } if (a->elem[1].u.data) { if (a->elem[1].type != SCRIPTVAR_ELEM_ST){ LM_ALERT("BUG in send() header type %d\n",a->elem[1].type); ret=E_BUG; break; } else { pve = (pv_elem_t *)a->elem[1].u.data; } } else { pve = NULL; } to=(union sockaddr_union*) pkg_malloc(sizeof(union sockaddr_union)); if (to==0){ LM_ERR("memory allocation failure\n"); ret=E_OUT_OF_MEM; break; } p=(struct proxy_l*)a->elem[0].u.data; ret=hostent2su(to, &p->host, p->addr_idx, (p->port)?p->port:SIP_PORT ); if (ret==0){ if (pve) { if ( pv_printf_s(msg, pve, &name_s)!=0 || name_s.len == 0 || name_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_UNSPEC; break; } /* build new msg */ tmp = pkg_malloc(msg->len + name_s.len); if (!tmp) { LM_ERR("memory allocation failure\n"); ret = E_OUT_OF_MEM; break; } LM_DBG("searching for first line %d\n", msg->first_line.len); /* search first line of previous msg */ /* copy headers */ len = msg->first_line.len; memcpy(tmp, msg->buf, len); memcpy(tmp + len, name_s.s, name_s.len); memcpy(tmp + len + name_s.len, msg->buf + len, msg->len - len); ret = msg_send(0/*send_sock*/, p->proto, to, 0/*id*/, tmp, msg->len + name_s.len); pkg_free(tmp); } else { ret = msg_send(0/*send_sock*/, p->proto, to, 0/*id*/, msg->buf, msg->len); } if (ret!=0 && p->host.h_addr_list[p->addr_idx+1]) p->addr_idx++; } pkg_free(to); if (ret==0) ret=1; break; case LOG_T: script_trace("core", "log", msg, a->line) ; if ((a->elem[0].type!=NUMBER_ST)|(a->elem[1].type!=STRING_ST)){ LM_ALERT("BUG in log() types %d, %d\n", a->elem[0].type, a->elem[1].type); ret=E_BUG; break; } LM_GEN1(a->elem[0].u.number, "%s", a->elem[1].u.string); ret=1; break; case APPEND_BRANCH_T: script_trace("core", "append_branch", msg, a->line) ; if ((a->elem[0].type!=STR_ST)) { LM_ALERT("BUG in append_branch %d\n", a->elem[0].type ); ret=E_BUG; break; } if (a->elem[0].u.s.s==NULL) { ret = append_branch(msg, 0, &msg->dst_uri, &msg->path_vec, get_ruri_q(), getb0flags(), msg->force_send_socket); /* reset all branch info */ msg->force_send_socket = 0; setb0flags(0); set_ruri_q(Q_UNSPECIFIED); if(msg->dst_uri.s!=0) pkg_free(msg->dst_uri.s); msg->dst_uri.s = 0; msg->dst_uri.len = 0; if(msg->path_vec.s!=0) pkg_free(msg->path_vec.s); msg->path_vec.s = 0; msg->path_vec.len = 0; } else { ret = append_branch(msg, &a->elem[0].u.s, &msg->dst_uri, &msg->path_vec, a->elem[1].u.number, getb0flags(), msg->force_send_socket); } break; case REMOVE_BRANCH_T: script_trace("core", "remove_branch", msg, a->line) ; if (a->elem[0].type == SCRIPTVAR_ST) { spec = (pv_spec_t*)a->elem[0].u.data; if( pv_get_spec_value(msg, spec, &val)!=0 || (val.flags&PV_VAL_NULL) || !(val.flags&PV_VAL_INT) ) { ret=-1; break; } i = val.ri; } else { i=a->elem[0].u.number; } ret = (remove_branch((unsigned int)i)==0)?1:-1; break; case LEN_GT_T: script_trace("core", "len_gt", msg, a->line) ; if (a->elem[0].type!=NUMBER_ST) { LM_ALERT("BUG in len_gt type %d\n", a->elem[0].type ); ret=E_BUG; break; } ret = (msg->len >= (unsigned int)a->elem[0].u.number) ? 1 : -1; break; case SET_DEBUG_T: script_trace("core", "set_debug", msg, a->line) ; if (a->elem[0].type==NUMBER_ST) set_proc_debug_level(a->elem[0].u.number); else reset_proc_debug_level(); ret = 1; break; case SETFLAG_T: script_trace("core", "setflag", msg, a->line) ; ret = setflag( msg, a->elem[0].u.number ); break; case RESETFLAG_T: script_trace("core", "resetflag", msg, a->line) ; ret = resetflag( msg, a->elem[0].u.number ); break; case ISFLAGSET_T: script_trace("core", "isflagset", msg, a->line) ; ret = isflagset( msg, a->elem[0].u.number ); break; case SETSFLAG_T: script_trace("core", "setsflag", msg, a->line) ; ret = setsflag( a->elem[0].u.number ); break; case RESETSFLAG_T: script_trace("core", "resetsflag", msg, a->line) ; ret = resetsflag( a->elem[0].u.number ); break; case ISSFLAGSET_T: script_trace("core", "issflagset", msg, a->line) ; ret = issflagset( a->elem[0].u.number ); break; case SETBFLAG_T: script_trace("core", "setbflag", msg, a->line) ; ret = setbflag( a->elem[0].u.number, a->elem[1].u.number ); break; case RESETBFLAG_T: script_trace("core", "resetbflag", msg, a->line) ; ret = resetbflag( a->elem[0].u.number, a->elem[1].u.number ); break; case ISBFLAGSET_T: script_trace("core", "isbflagset", msg, a->line) ; ret = isbflagset( a->elem[0].u.number, a->elem[1].u.number ); break; case ERROR_T: script_trace("core", "error", msg, a->line) ; if ((a->elem[0].type!=STRING_ST)|(a->elem[1].type!=STRING_ST)){ LM_ALERT("BUG in error() types %d, %d\n", a->elem[0].type, a->elem[1].type); ret=E_BUG; break; } LM_ERR("error(\"%s\", \"%s\") not implemented yet\n", a->elem[0].u.string, a->elem[1].u.string); ret=1; break; case ROUTE_T: script_trace("route", rlist[a->elem[0].u.number].name, msg, a->line) ; if (a->elem[0].type!=NUMBER_ST){ LM_ALERT("BUG in route() type %d\n", a->elem[0].type); ret=E_BUG; break; } if ((a->elem[0].u.number>RT_NO)||(a->elem[0].u.number<0)){ LM_ALERT("BUG - invalid routing table number in" "route(%lu)\n", a->elem[0].u.number); ret=E_CFG; break; } /* check if the route has parameters */ if (a->elem[1].type != 0) { if (a->elem[1].type != NUMBER_ST || a->elem[2].type != SCRIPTVAR_ELEM_ST) { LM_ALERT("BUG in route() type %d/%d\n", a->elem[1].type, a->elem[2].type); ret=E_BUG; break; } route_params_bak = route_params; route_params = (action_elem_t *)a->elem[2].u.data; route_params_number_bak = route_params_number; route_params_number = a->elem[1].u.number; return_code=run_actions(rlist[a->elem[0].u.number].a, msg); route_params = route_params_bak; route_params_number = route_params_number_bak; } else { return_code=run_actions(rlist[a->elem[0].u.number].a, msg); } ret=return_code; break; case REVERT_URI_T: script_trace("core", "revert_uri", msg, a->line) ; if (msg->new_uri.s) { pkg_free(msg->new_uri.s); msg->new_uri.len=0; msg->new_uri.s=0; msg->parsed_uri_ok=0; /* invalidate current parsed uri*/ }; ret=1; break; case SET_HOST_T: case SET_HOSTPORT_T: case SET_USER_T: case SET_USERPASS_T: case SET_PORT_T: case SET_URI_T: case PREFIX_T: case STRIP_T: case STRIP_TAIL_T: script_trace("core", (unsigned char)a->type == SET_HOST_T ? "set_host" : (unsigned char)a->type == SET_HOSTPORT_T ? "set_hostport" : (unsigned char)a->type == SET_USER_T ? "set_user" : (unsigned char)a->type == SET_USERPASS_T ? "set_userpass" : (unsigned char)a->type == SET_PORT_T ? "set_port" : (unsigned char)a->type == SET_URI_T ? "set_uri" : (unsigned char)a->type == PREFIX_T ? "prefix" : (unsigned char)a->type == STRIP_T ? "strip" : "strip_tail", msg, a->line); user=0; if (a->type==STRIP_T || a->type==STRIP_TAIL_T) { if (a->elem[0].type!=NUMBER_ST) { LM_ALERT("BUG in set*() type %d\n", a->elem[0].type); break; } } else if (a->elem[0].type!=STR_ST){ LM_ALERT("BUG in set*() type %d\n", a->elem[0].type); ret=E_BUG; break; } if (a->type==SET_URI_T) { if (set_ruri( msg, &a->elem[0].u.s) ) { LM_ERR("failed to set new RURI\n"); ret=E_OUT_OF_MEM; break; } ret=1; break; } if (msg->new_uri.s) { tmp=msg->new_uri.s; len=msg->new_uri.len; }else{ tmp=msg->first_line.u.request.uri.s; len=msg->first_line.u.request.uri.len; } if (parse_uri(tmp, len, &uri)<0){ LM_ERR("bad uri <%.*s>, dropping packet\n", len, tmp); ret=E_UNSPEC; break; } new_uri=pkg_malloc(MAX_URI_SIZE); if (new_uri==0){ LM_ERR("memory allocation failure\n"); ret=E_OUT_OF_MEM; break; } end=new_uri+MAX_URI_SIZE; crt=new_uri; /* begin copying */ len = (uri.user.len?uri.user.s:uri.host.s) - tmp; if (crt+len>end) goto error_uri; memcpy(crt,tmp,len);crt+=len; if (a->type==PREFIX_T) { if (crt+a->elem[0].u.s.len>end) goto error_uri; memcpy( crt, a->elem[0].u.s.s, a->elem[0].u.s.len); crt+=a->elem[0].u.s.len; /* whatever we had before, with prefix we have username now */ user=1; } if ((a->type==SET_USER_T)||(a->type==SET_USERPASS_T)) { tmp=a->elem[0].u.s.s; len=a->elem[0].u.s.len; } else if (a->type==STRIP_T) { if (a->elem[0].u.number>uri.user.len) { LM_WARN("too long strip asked; " " deleting username: %lu of <%.*s>\n", a->elem[0].u.number, uri.user.len, uri.user.s); len=0; } else if (a->elem[0].u.number==uri.user.len) { len=0; } else { tmp=uri.user.s + a->elem[0].u.number; len=uri.user.len - a->elem[0].u.number; } } else if (a->type==STRIP_TAIL_T) { if (a->elem[0].u.number>uri.user.len) { LM_WARN("too long strip_tail asked;" " deleting username: %lu of <%.*s>\n", a->elem[0].u.number, uri.user.len, uri.user.s); len=0; } else if (a->elem[0].u.number==uri.user.len) { len=0; } else { tmp=uri.user.s; len=uri.user.len - a->elem[0].u.number; } } else { tmp=uri.user.s; len=uri.user.len; } if (len){ if(crt+len>end) goto error_uri; memcpy(crt,tmp,len);crt+=len; user=1; /* we have an user field so mark it */ } if (a->type==SET_USERPASS_T) tmp=0; else tmp=uri.passwd.s; /* passwd */ if (tmp){ len=uri.passwd.len; if(crt+len+1>end) goto error_uri; *crt=':'; crt++; memcpy(crt,tmp,len);crt+=len; } /* host */ if (user || tmp){ /* add @ */ if(crt+1>end) goto error_uri; *crt='@'; crt++; } if ((a->type==SET_HOST_T) ||(a->type==SET_HOSTPORT_T)) { tmp=a->elem[0].u.s.s; len=a->elem[0].u.s.len; } else { tmp=uri.host.s; len = uri.host.len; } if (tmp){ if(crt+len>end) goto error_uri; memcpy(crt,tmp,len);crt+=len; } /* port */ if (a->type==SET_HOSTPORT_T) tmp=0; else if (a->type==SET_PORT_T) { tmp=a->elem[0].u.s.s; len=a->elem[0].u.s.len; } else { tmp=uri.port.s; len = uri.port.len; } if (tmp && len>0){ if(crt+len+1>end) goto error_uri; *crt=':'; crt++; memcpy(crt,tmp,len);crt+=len; } /* params */ tmp=uri.params.s; if (tmp){ /* include in param string the starting ';' */ len=uri.params.len+1; tmp--; if(crt+len+1>end) goto error_uri; /* if a maddr param is present, strip it out */ if (uri.maddr.len && (a->type==SET_HOSTPORT_T || a->type==SET_HOST_T)) { memcpy(crt,tmp,uri.maddr.s-tmp-1); crt+=uri.maddr.s-tmp-1; memcpy(crt,uri.maddr_val.s+uri.maddr_val.len, tmp+len-uri.maddr_val.s-uri.maddr_val.len); crt+=tmp+len-uri.maddr_val.s-uri.maddr_val.len; } else { memcpy(crt,tmp,len);crt+=len; } } /* headers */ tmp=uri.headers.s; if (tmp){ len=uri.headers.len; if(crt+len+1>end) goto error_uri; *crt='?'; crt++; memcpy(crt,tmp,len);crt+=len; } *crt=0; /* null terminate the thing */ /* copy it to the msg */ if (msg->new_uri.s) pkg_free(msg->new_uri.s); msg->new_uri.s=new_uri; msg->new_uri.len=crt-new_uri; msg->parsed_uri_ok=0; ret=1; break; case SET_DSTURI_T: script_trace("core", "set_dsturi", msg, a->line) ; if (a->elem[0].type!=STR_ST){ LM_ALERT("BUG in setdsturi() type %d\n", a->elem[0].type); ret=E_BUG; break; } if(set_dst_uri(msg, &a->elem[0].u.s)!=0) ret = -1; else ret = 1; break; case SET_DSTHOST_T: case SET_DSTPORT_T: script_trace("core", (unsigned char) a->type == SET_DSTHOST_T ? "set_dsturi" : "set_dstport", msg, a->line); if (a->elem[0].type!=STR_ST){ LM_ALERT("BUG in domain setting type %d\n", a->elem[0].type); ret=E_BUG; break; } tmp = msg->dst_uri.s; len = msg->dst_uri.len; if (tmp == NULL || len == 0) { LM_ERR("failure - null uri\n"); ret = E_UNSPEC; break; } if (a->type == SET_DSTHOST_T && (a->elem[0].u.s.s == NULL || a->elem[0].u.s.len == 0)) { LM_ERR("cannot set a null uri domain\n"); break; } if (parse_uri(tmp, len, &uri)<0) { LM_ERR("bad uri <%.*s>, dropping packet\n", len, tmp); break; } new_uri=pkg_malloc(MAX_URI_SIZE); if (new_uri == NULL) { LM_ERR("memory allocation failure\n"); ret=E_OUT_OF_MEM; break; } end=new_uri+MAX_URI_SIZE; crt=new_uri; len = (uri.user.len?uri.user.s:uri.host.s) - tmp; if (crt+len>end) goto error_uri; memcpy(crt,tmp,len); crt += len; /* user */ tmp = uri.user.s; len = uri.user.len; if (tmp) { if (crt+len>end) goto error_uri; memcpy(crt,tmp,len); crt += len; user = 1; } /* passwd */ tmp = uri.passwd.s; len = uri.passwd.len; if (user || tmp) { if (crt+len+1>end) goto error_uri; *crt++=':'; memcpy(crt, tmp, len); crt += len; } /* host */ if (a->type==SET_DSTHOST_T) { tmp = a->elem[0].u.s.s; len = a->elem[0].u.s.len; } else { tmp = uri.host.s; len = uri.host.len; } if (tmp) { if (user) { if (crt+1>end) goto error_uri; *crt++='@'; } if (crt+len+1>end) goto error_uri; memcpy(crt, tmp, len); crt += len; } /* port */ if (a->type==SET_DSTPORT_T) { tmp = a->elem[0].u.s.s; len = a->elem[0].u.s.len; } else { tmp = uri.port.s; len = uri.port.len; } if (tmp) { if (crt+len+1>end) goto error_uri; *crt++=':'; memcpy(crt, tmp, len); crt += len; } /* params */ tmp=uri.params.s; if (tmp){ len=uri.params.len; if(crt+len+1>end) goto error_uri; *crt++=';'; memcpy(crt,tmp,len); crt += len; } /* headers */ tmp=uri.headers.s; if (tmp){ len=uri.headers.len; if(crt+len+1>end) goto error_uri; *crt++='?'; memcpy(crt,tmp,len); crt += len; } *crt=0; /* null terminate the thing */ /* copy it to the msg */ pkg_free(msg->dst_uri.s); msg->dst_uri.s=new_uri; msg->dst_uri.len=crt-new_uri; ret = 1; break; case RESET_DSTURI_T: script_trace("core", "reset_dsturi", msg, a->line) ; if(msg->dst_uri.s!=0) pkg_free(msg->dst_uri.s); msg->dst_uri.s = 0; msg->dst_uri.len = 0; ret = 1; break; case ISDSTURISET_T: script_trace("core", "isdsturiset", msg, a->line) ; if(msg->dst_uri.s==0 || msg->dst_uri.len<=0) ret = -1; else ret = 1; break; case IF_T: script_trace("core", "if", msg, a->line) ; /* if null expr => ignore if? */ if ((a->elem[0].type==EXPR_ST)&&a->elem[0].u.data){ v=eval_expr((struct expr*)a->elem[0].u.data, msg, 0); /* set return code to expr value */ if (v<0 || (action_flags&ACT_FL_RETURN) || (action_flags&ACT_FL_EXIT) ){ if (v==EXPR_DROP || (action_flags&ACT_FL_RETURN) || (action_flags&ACT_FL_EXIT) ){ /* hack to quit on DROP*/ ret=0; return_code = 0; break; }else{ LM_WARN("error in expression (l=%d)\n", a->line); } } ret=1; /*default is continue */ if (v>0) { if ((a->elem[1].type==ACTIONS_ST)&&a->elem[1].u.data){ ret=run_action_list( (struct action*)a->elem[1].u.data,msg ); return_code = ret; } else return_code = v; }else{ if ((a->elem[2].type==ACTIONS_ST)&&a->elem[2].u.data){ ret=run_action_list( (struct action*)a->elem[2].u.data,msg); return_code = ret; } else return_code = v; } } break; case WHILE_T: script_trace("core", "while", msg, a->line) ; /* if null expr => ignore if? */ if ((a->elem[0].type==EXPR_ST)&&a->elem[0].u.data){ len = 0; while(1) { if(len++ >= max_while_loops) { LM_INFO("max while loops are encountered\n"); break; } v=eval_expr((struct expr*)a->elem[0].u.data, msg, 0); /* set return code to expr value */ if (v<0 || (action_flags&ACT_FL_RETURN) || (action_flags&ACT_FL_EXIT) ){ if (v==EXPR_DROP || (action_flags&ACT_FL_RETURN) || (action_flags&ACT_FL_EXIT) ){ ret=0; return_code = 0; break; }else{ LM_WARN("error in expression (l=%d)\n", a->line); } } ret=1; /*default is continue */ if (v>0) { if ((a->elem[1].type==ACTIONS_ST) &&a->elem[1].u.data){ ret=run_action_list( (struct action*)a->elem[1].u.data,msg ); /* check if return was done */ if ((action_flags&ACT_FL_RETURN) || (action_flags&ACT_FL_EXIT) ){ break; } return_code = ret; } else { /* we should not get here */ return_code = v; break; } } else { /* condition was false */ return_code = v; break; } } } break; case CACHE_STORE_T: script_trace("core", "cache_store", msg, a->line) ; if ((a->elem[0].type!=STR_ST)) { LM_ALERT("BUG in cache_store() - first argument not of" " type string [%d]\n", a->elem[0].type ); ret=E_BUG; break; } if ((a->elem[1].type!=STR_ST)) { LM_ALERT("BUG in cache_store() - second argument not of " "type string [%d]\n", a->elem[1].type ); ret=E_BUG; break; } if ((a->elem[2].type!=STR_ST)) { LM_ALERT("BUG in cache_store() - third argument not of type" " string%d\n", a->elem[2].type ); ret=E_BUG; break; } str val_s; /* parse the name argument */ pve = (pv_elem_t *)a->elem[1].u.data; if ( pv_printf_s(msg, pve, &name_s)!=0 || name_s.len == 0 || name_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; break; } /* parse the value argument */ pve = (pv_elem_t *)a->elem[2].u.data; if ( pv_printf_s(msg, pve, &val_s)!=0 || val_s.len == 0 || val_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; break; } /* get the expires value */ if ( a->elem[3].type == SCRIPTVAR_ST ) { spec = (pv_spec_t*)a->elem[3].u.data; memset(&val, 0, sizeof(pv_value_t)); if(pv_get_spec_value(msg, spec, &val) < 0) { LM_DBG("Failed to get scriptvar value while executing cache_store\n"); ret=E_BUG; break; } if (!(val.flags&PV_VAL_INT)) { LM_ERR("Wrong value for cache_store expires, not an integer [%.*s]\n", val.rs.len, val.rs.s); } expires = val.ri; } else if ( a->elem[3].type == NUMBER_ST ) { expires = (int)a->elem[3].u.number; } ret = cachedb_store( &a->elem[0].u.s, &name_s, &val_s,expires); break; case CACHE_REMOVE_T: script_trace("core", "cache_remove", msg, a->line) ; if ((a->elem[0].type!=STR_ST)) { LM_ALERT("BUG in cache_remove() %d\n", a->elem[0].type ); ret=E_BUG; break; } if ((a->elem[1].type!=STR_ST)) { LM_ALERT("BUG in cache_remove() %d\n", a->elem[1].type ); ret=E_BUG; break; } /* parse the name argument */ pve = (pv_elem_t *)a->elem[1].u.data; if ( pv_printf_s(msg, pve, &name_s)!=0 || name_s.len == 0 || name_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; break; } ret = cachedb_remove( &a->elem[0].u.s, &name_s); break; case CACHE_FETCH_T: script_trace("core", "cache_fetch", msg, a->line) ; if ((a->elem[0].type!=STR_ST)) { LM_ALERT("BUG in cache_fetch() %d\n", a->elem[0].type ); ret=E_BUG; break; } if ((a->elem[1].type!=STR_ST)) { LM_ALERT("BUG in cache_fetch() %d\n", a->elem[1].type ); ret=E_BUG; break; } if (a->elem[2].type!=SCRIPTVAR_ST){ LM_ALERT("BUG in cache_fetch() type %d\n", a->elem[2].type); ret=E_BUG; break; } str aux = {0, 0}; /* parse the name argument */ pve = (pv_elem_t *)a->elem[1].u.data; if ( pv_printf_s(msg, pve, &name_s)!=0 || name_s.len == 0 || name_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; break; } ret = cachedb_fetch( &a->elem[0].u.s, &name_s, &aux); if(ret > 0) { val.rs = aux; val.flags = PV_VAL_STR; spec = (pv_spec_t*)a->elem[2].u.data; if (pv_set_value(msg, spec, 0, &val) < 0) { LM_ERR("cannot set the variable value\n"); pkg_free(aux.s); return -1; } pkg_free(aux.s); } break; case CACHE_COUNTER_FETCH_T: script_trace("core", "cache_counter_fetch", msg, a->line) ; if ((a->elem[0].type!=STR_ST)) { LM_ALERT("BUG in cache_fetch() %d\n", a->elem[0].type ); ret=E_BUG; break; } if ((a->elem[1].type!=STR_ST)) { LM_ALERT("BUG in cache_fetch() %d\n", a->elem[1].type ); ret=E_BUG; break; } if (a->elem[2].type!=SCRIPTVAR_ST){ LM_ALERT("BUG in cache_fetch() type %d\n", a->elem[2].type); ret=E_BUG; break; } int aux_counter; /* parse the name argument */ pve = (pv_elem_t *)a->elem[1].u.data; if ( pv_printf_s(msg, pve, &name_s)!=0 || name_s.len == 0 || name_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; break; } ret = cachedb_counter_fetch( &a->elem[0].u.s, &name_s, &aux_counter); if(ret > 0) { val.ri = aux_counter; val.flags = PV_TYPE_INT|PV_VAL_INT; spec = (pv_spec_t*)a->elem[2].u.data; if (pv_set_value(msg, spec, 0, &val) < 0) { LM_ERR("cannot set the variable value\n"); pkg_free(aux.s); return -1; } } break; case CACHE_ADD_T: script_trace("core", "cache_add", msg, a->line) ; if ((a->elem[0].type!=STR_ST)) { LM_ALERT("BUG in cache_add() - first argument not of" " type string [%d]\n", a->elem[0].type ); ret=E_BUG; break; } if ((a->elem[1].type!=STR_ST)) { LM_ALERT("BUG in cache_add() - second argument not of " "type string [%d]\n", a->elem[1].type ); ret=E_BUG; break; } /* parse the name argument */ pve = (pv_elem_t *)a->elem[1].u.data; if ( pv_printf_s(msg, pve, &name_s)!=0 || name_s.len == 0 || name_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; break; } int increment=0; /* get the increment value */ if ( a->elem[2].type == SCRIPTVAR_ST ) { spec = (pv_spec_t*)a->elem[2].u.data; memset(&val, 0, sizeof(pv_value_t)); if(pv_get_spec_value(msg, spec, &val) < 0) { LM_DBG("Failed to get scriptvar value while executing cache_add\n"); ret=E_BUG; break; } if (!(val.flags&PV_VAL_INT)) { LM_ERR("Wrong value for cache_add, not an integer [%.*s]\n", val.rs.len, val.rs.s); } increment = val.ri; } else if ( a->elem[2].type == NUMBER_ST ) { increment = (int)a->elem[2].u.number; } expires = (int)a->elem[3].u.number; /* TODO - return the new value to script ? */ ret = cachedb_add(&a->elem[0].u.s, &name_s, increment,expires,NULL); break; case CACHE_SUB_T: script_trace("core", "cache_sub", msg, a->line) ; if ((a->elem[0].type!=STR_ST)) { LM_ALERT("BUG in cache_sub() - first argument not of" " type string [%d]\n", a->elem[0].type ); ret=E_BUG; break; } if ((a->elem[1].type!=STR_ST)) { LM_ALERT("BUG in cache_sub() - second argument not of " "type string [%d]\n", a->elem[1].type ); ret=E_BUG; break; } /* parse the name argument */ pve = (pv_elem_t *)a->elem[1].u.data; if ( pv_printf_s(msg, pve, &name_s)!=0 || name_s.len == 0 || name_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; break; } int decrement=0; /* get the increment value */ if ( a->elem[2].type == SCRIPTVAR_ST ) { spec = (pv_spec_t*)a->elem[2].u.data; memset(&val, 0, sizeof(pv_value_t)); if(pv_get_spec_value(msg, spec, &val) < 0) { LM_DBG("Failed to get scriptvar value while executing cache_sub\n"); ret=E_BUG; break; } if (!(val.flags&PV_VAL_INT)) { LM_ERR("Wrong value for cache_sub, not an integer [%.*s]\n", val.rs.len, val.rs.s); } decrement = val.ri; } else if ( a->elem[2].type == NUMBER_ST ) { decrement = (int)a->elem[2].u.number; } expires = (int)a->elem[3].u.number; /* TODO - return new value to script ? */ ret = cachedb_sub(&a->elem[0].u.s, &name_s, decrement,expires,NULL); break; case CACHE_RAW_QUERY_T: if ((a->elem[0].type!=STR_ST)) { LM_ALERT("BUG in cache_fetch() %d\n", a->elem[0].type ); ret=E_BUG; break; } if ((a->elem[1].type!=STR_ST)) { LM_ALERT("BUG in cache_fetch() %d\n", a->elem[1].type ); ret=E_BUG; break; } if (a->elem[2].u.data != NULL && a->elem[2].type!=STR_ST){ LM_ALERT("BUG in cache_raw_query() type %d\n", a->elem[2].type); ret=E_BUG; break; } /* parse the name argument */ pve = (pv_elem_t *)a->elem[1].u.data; if ( pv_printf_s(msg, pve, &name_s)!=0 || name_s.len == 0 || name_s.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; break; } cdb_raw_entry **cdb_reply; int val_number=0,i,j; int key_number=0; pvname_list_t *cdb_res,*it; int_str avp_val; int_str avp_name; unsigned short avp_type; if (a->elem[2].u.data) { cdb_res = (pvname_list_t*)a->elem[2].u.data; for (it=cdb_res;it;it=it->next) val_number++; LM_DBG("The query expects %d results back\n",val_number); ret = cachedb_raw_query( &a->elem[0].u.s, &name_s, &cdb_reply,val_number,&key_number); if (ret >= 0 && val_number > 0) { for (i=key_number-1; i>=0;i--) { it=cdb_res; for (j=0;j < val_number;j++) { avp_type = 0; if (pv_get_avp_name(msg,&it->sname.pvp,&avp_name.n, &avp_type) != 0) { LM_ERR("cannot get avp name [%d/%d]\n",i,j); goto next_avp; } switch (cdb_reply[i][j].type) { case CDB_INT: avp_val.n = cdb_reply[i][j].val.n; break; case CDB_STR: avp_type |= AVP_VAL_STR; avp_val.s = cdb_reply[i][j].val.s; break; default: LM_WARN("Unknown type %d\n",cdb_reply[i][j].type); goto next_avp; } if (add_avp(avp_type,avp_name.n,avp_val) != 0) { LM_ERR("Unable to add AVP\n"); free_raw_fetch(cdb_reply,val_number,key_number); return -1; } next_avp: if (it) { it = it->next; if (it==NULL); break; } } } free_raw_fetch(cdb_reply,val_number,key_number); } } else ret = cachedb_raw_query( &a->elem[0].u.s, &name_s, NULL,0,NULL); break; case XDBG_T: script_trace("core", "xdbg", msg, a->line) ; if (a->elem[0].type == SCRIPTVAR_ELEM_ST) { if (xdbg(msg, a->elem[0].u.data, val.rs.s) < 0) { LM_ALERT("Cannot print message"); break; } } else { LM_ALERT("BUG in xdbg() type %d\n", a->elem[0].type); ret=E_BUG; } break; case XLOG_T: script_trace("core", "xlog", msg, a->line) ; if (a->elem[1].u.data != NULL) { if (a->elem[1].type != SCRIPTVAR_ELEM_ST) { LM_ALERT("BUG in xlog() type %d\n", a->elem[1].type); ret=E_BUG; break; } if (a->elem[0].type != STR_ST) { LM_ALERT("BUG in xlog() type %d\n", a->elem[0].type); ret=E_BUG; break; } if (xlog_2(msg,a->elem[0].u.data, a->elem[1].u.data) < 0) { LM_ALERT("Cannot print xlog debug message"); break; } } else { if (a->elem[0].type != SCRIPTVAR_ELEM_ST) { LM_ALERT("BUG in xlog() type %d\n", a->elem[0].type); ret=E_BUG; break; } if (xlog_1(msg,a->elem[0].u.data, val.rs.s) < 0) { LM_ALERT("Cannot print xlog debug message"); break; } } break; case RAISE_EVENT_T: script_trace("core", "raise_event", msg, a->line) ; if (a->elem[0].type != NUMBER_ST) { LM_ERR("invalid event id\n"); ret=E_BUG; break; } if (a->elem[2].u.data) { /* three parameters specified */ ret = evi_raise_script_event(msg, (event_id_t)a->elem[0].u.number, a->elem[1].u.data, a->elem[2].u.data); } else { /* two parameters specified */ ret = evi_raise_script_event(msg, (event_id_t)a->elem[0].u.number, NULL, a->elem[1].u.data); } if (ret <= 0) { LM_ERR("cannot raise event\n"); ret=E_UNSPEC; break; } break; case SUBSCRIBE_EVENT_T: script_trace("core", "subscribe_event", msg, a->line) ; if (a->elem[0].type != STR_ST || a->elem[1].type != STR_ST) { LM_ERR("BUG in subscribe arguments\n"); ret=E_BUG; break; } if (a->elem[2].u.data) { if (a->elem[2].type != NUMBER_ST) { LM_ERR("BUG in subscribe expiration time\n"); ret=E_BUG; break; } else { i = a->elem[2].u.number; } } else { i = 0; } name_s.s = a->elem[0].u.data; name_s.len = strlen(name_s.s); /* result should be the socket */ result.s = a->elem[1].u.data; result.len = strlen(result.s); ret = evi_event_subscribe(name_s, result, i, 0); break; case CONSTRUCT_URI_T: script_trace("core", "construct_uri", msg, a->line) ; for (i=0;i<5;i++) { pve = (pv_elem_t *)a->elem[i].u.data; if (pve->spec.getf) { if ( pv_printf_s(msg, pve, &vals[i])!=0 || vals[i].len == 0 || vals[i].s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; return -1; } } else vals[i] = pve->text; } result.s = construct_uri(&vals[0],&vals[1],&vals[2],&vals[3],&vals[4], &result.len); if (result.s) { int_str res; int avp_name; unsigned short avp_type; spec = (pv_spec_t*)a->elem[5].u.data; if (pv_get_avp_name( msg, &(spec->pvp), &avp_name, &avp_type)!=0){ LM_CRIT("BUG in getting AVP name\n"); return -1; } res.s = result; if (add_avp(AVP_VAL_STR|avp_type, avp_name, res)<0){ LM_ERR("cannot add AVP\n"); return -1; } } break; case GET_TIMESTAMP_T: script_trace("core", "get_timestamp", msg, a->line) ; if (get_timestamp(&sec,&usec) == 0) { int avp_name; int_str res; unsigned short avp_type; spec = (pv_spec_t*)a->elem[0].u.data; if (pv_get_avp_name(msg, &(spec->pvp), &avp_name, &avp_type) != 0) { LM_CRIT("BUG in getting AVP name\n"); return -1; } res.n = sec; if (add_avp(avp_type, avp_name, res) < 0) { LM_ERR("cannot add AVP\n"); return -1; } spec = (pv_spec_t*)a->elem[1].u.data; if (pv_get_avp_name(msg, &(spec->pvp), &avp_name, &avp_type) != 0) { LM_CRIT("BUG in getting AVP name\n"); return -1; } res.n = usec; if (add_avp(avp_type, avp_name, res) < 0) { LM_ERR("cannot add AVP\n"); return -1; } } else { LM_ERR("failed to get time\n"); return -1; } break; case SWITCH_T: script_trace("core", "switch", msg, a->line) ; if (a->elem[0].type!=SCRIPTVAR_ST){ LM_ALERT("BUG in switch() type %d\n", a->elem[0].type); ret=E_BUG; break; } spec = (pv_spec_t*)a->elem[0].u.data; if(pv_get_spec_value(msg, spec, &val)!=0) { LM_ALERT("BUG - no value in switch()\n"); ret=E_BUG; break; } /* get the value of pvar */ if(a->elem[1].type!=ACTIONS_ST) { LM_ALERT("BUG in switch() actions\n"); ret=E_BUG; break; } return_code=1; adefault = NULL; aitem = (struct action*)a->elem[1].u.data; cmatch=0; while(aitem) { if((unsigned char)aitem->type==DEFAULT_T) adefault=aitem; if(cmatch==0) { if(aitem->elem[0].type==STR_ST) { if(val.flags&PV_VAL_STR && val.rs.len==aitem->elem[0].u.s.len && strncasecmp(val.rs.s, aitem->elem[0].u.s.s, val.rs.len)==0) cmatch = 1; } else { /* number */ if(val.flags&PV_VAL_INT && val.ri==aitem->elem[0].u.number) cmatch = 1; } } if(cmatch==1) { if(aitem->elem[1].u.data) { return_code=run_action_list( (struct action*)aitem->elem[1].u.data, msg); if ((action_flags&ACT_FL_RETURN) || (action_flags&ACT_FL_EXIT)) break; } if(aitem->elem[2].u.number==1) break; } aitem = aitem->next; } if((cmatch==0) && (adefault!=NULL)) { LM_DBG("switch: running default statement\n"); if(adefault->elem[0].u.data) return_code=run_action_list( (struct action*)adefault->elem[0].u.data, msg); } ret=return_code; break; case MODULE_T: script_trace("module", ((cmd_export_t*)(a->elem[0].u.data))->name, msg, a->line) ; if ( (a->elem[0].type==CMD_ST) && a->elem[0].u.data ) { ret=((cmd_export_t*)(a->elem[0].u.data))->function(msg, (char*)a->elem[1].u.data, (char*)a->elem[2].u.data, (char*)a->elem[3].u.data, (char*)a->elem[4].u.data, (char*)a->elem[5].u.data, (char*)a->elem[6].u.data); }else{ LM_ALERT("BUG in module call\n"); } break; case FORCE_RPORT_T: script_trace("core", "force_rport", msg, a->line) ; msg->msg_flags|=FL_FORCE_RPORT; ret=1; /* continue processing */ break; case FORCE_LOCAL_RPORT_T: script_trace("core", "force_local_rport", msg, a->line) ; msg->msg_flags|=FL_FORCE_LOCAL_RPORT; ret=1; /* continue processing */ break; case SET_ADV_ADDR_T: script_trace("core", "set_adv_addr", msg, a->line) ; if (a->elem[0].type!=STR_ST){ LM_ALERT("BUG in set_advertised_address() " "type %d\n", a->elem[0].type); ret=E_BUG; break; } str adv_addr; pve = (pv_elem_t *)a->elem[0].u.data; if ( pv_printf_s(msg, pve, &adv_addr)!=0 || adv_addr.len == 0 || adv_addr.s == NULL) { LM_WARN("cannot get string for value\n"); ret=E_BUG; break; } LM_DBG("adv address = [%.*s]\n",adv_addr.len,adv_addr.s); msg->set_global_address=adv_addr; ret=1; /* continue processing */ break; case SET_ADV_PORT_T: script_trace("core", "set_adv_port", msg, a->line) ; if (a->elem[0].type!=STR_ST){ LM_ALERT("BUG in set_advertised_port() " "type %d\n", a->elem[0].type); ret=E_BUG; break; } msg->set_global_port=*((str*)a->elem[0].u.data); ret=1; /* continue processing */ break; #ifdef USE_TCP case FORCE_TCP_ALIAS_T: script_trace("core", "force_tcp_alias", msg, a->line) ; if ( msg->rcv.proto==PROTO_TCP #ifdef USE_TLS || msg->rcv.proto==PROTO_TLS #endif ){ if (a->elem[0].type==NOSUBTYPE) port=msg->via1->port; else if (a->elem[0].type==NUMBER_ST) port=(int)a->elem[0].u.number; else{ LM_ALERT("BUG in force_tcp_alias" " port type %d\n", a->elem[0].type); ret=E_BUG; break; } if (tcpconn_add_alias(msg->rcv.proto_reserved1, port, msg->rcv.proto)!=0){ LM_ERR("tcp alias failed\n"); ret=E_UNSPEC; break; } } #endif ret=1; /* continue processing */ break; case FORCE_SEND_SOCKET_T: script_trace("core", "force_send_socket", msg, a->line) ; if (a->elem[0].type!=SOCKETINFO_ST){ LM_ALERT("BUG in force_send_socket argument" " type: %d\n", a->elem[0].type); ret=E_BUG; break; } msg->force_send_socket=(struct socket_info*)a->elem[0].u.data; ret=1; /* continue processing */ break; case SERIALIZE_BRANCHES_T: script_trace("core", "serialize_branches", msg, a->line) ; if (a->elem[0].type!=NUMBER_ST){ LM_ALERT("BUG in serialize_branches argument" " type: %d\n", a->elem[0].type); ret=E_BUG; break; } if (serialize_branches(msg,(int)a->elem[0].u.number)!=0) { LM_ERR("serialize_branches failed\n"); ret=E_UNSPEC; break; } ret=1; /* continue processing */ break; case NEXT_BRANCHES_T: script_trace("core", "next_branches", msg, a->line) ; if ((ret=next_branches(msg))<0) { LM_ERR("next_branches failed\n"); ret=E_UNSPEC; break; } /* continue processing */ break; case EQ_T: case COLONEQ_T: case PLUSEQ_T: case MINUSEQ_T: case DIVEQ_T: case MULTEQ_T: case MODULOEQ_T: case BANDEQ_T: case BOREQ_T: case BXOREQ_T: ret = do_assign(msg, a); break; case USE_BLACKLIST_T: script_trace("core", "use_blacklist", msg, a->line) ; mark_for_search((struct bl_head*)a->elem[0].u.data, 1); break; case UNUSE_BLACKLIST_T: script_trace("core", "unuse_blacklist", msg, a->line); mark_for_search((struct bl_head*)a->elem[0].u.data, 0); break; case PV_PRINTF_T: script_trace("core", "pv_printf", msg, a->line); ret = -1; spec = (pv_spec_p)a->elem[0].u.data; if(!pv_is_w(spec)) { LM_ERR("read only PV in first parameter of pv_printf\n"); goto error; } model = (pv_elem_p)a->elem[1].u.data; memset(&val, 0, sizeof(pv_value_t)); if(pv_printf_s(msg, model, &val.rs)!=0) { LM_ERR("cannot eval second parameter\n"); goto error; } val.flags = PV_VAL_STR; if(pv_set_value(msg, spec, EQ_T, &val)<0) { LM_ERR("setting PV failed\n"); goto error; } ret = 1; break; case SCRIPT_TRACE_T: script_trace("core", "script_trace", msg, a->line); if (a->elem[0].type==NOSUBTYPE) { use_script_trace = 0; } else { use_script_trace = 1; if (a->elem[0].type != NUMBER_ST || a->elem[1].type != SCRIPTVAR_ELEM_ST) { LM_ERR("BUG in use_script_trace() arguments\n"); ret=E_BUG; break; } if (a->elem[2].type!=NOSUBTYPE) { script_trace_info = (char *)a->elem[2].u.data; } else { script_trace_info = NULL; } script_trace_log_level = (int)a->elem[0].u.number; script_trace_elem = *(pv_elem_p)a->elem[1].u.data; } break; default: LM_ALERT("BUG - unknown type %d\n", a->type); goto error; } if((unsigned char)a->type!=IF_T && (unsigned char)a->type!=ROUTE_T) return_code = ret; /*skip:*/ update_longest_action(); return ret; error: LM_ERR("error at line: %d\n", a->line); update_longest_action(); return ret; error_uri: LM_ERR("set*: uri too long\n"); if (new_uri) pkg_free(new_uri); update_longest_action(); return E_UNSPEC; error_fwd_uri: update_longest_action(); return ret; }
/* * 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; }
/* * 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); 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 (set_ruri(_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) == -1) { goto done; } } } done: free_rdata_list(head); return first ? -1 : 1; }
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; }