/* Encode branch info from contact struct to str */ static inline int encode_branch_info(str *info, struct contact *con) { char *at, *s; int len; info->len = con->uri.len + con->dst_uri.len + con->path.len + MAX_SOCKET_STR + INT2STR_MAX_LEN + 5; info->s = pkg_malloc(info->len); if (!info->s) { LM_ERR("no memory left for branch info\n"); return 0; } at = info->s; append_str(at, con->uri.s, con->uri.len); append_chr(at, '\n'); append_str(at, con->dst_uri.s, con->dst_uri.len); append_chr(at, '\n'); append_str(at, con->path.s, con->path.len); append_chr(at, '\n'); if (con->sock) { len = MAX_SOCKET_STR; if (socket2str(at, &len, con->sock) < 0) { LM_ERR("failed to convert socket to str\n"); return 0; } } else { len = 0; } at = at + len; append_chr(at, '\n'); s = int2str(con->flags, &len); append_str(at, s, len); append_chr(at, '\n'); info->len = at - info->s + 1; return 1; }
/* * Set userpart of URI */ int set_uri_user(struct sip_msg* _m, char* _uri, char* _value) { pv_spec_t *uri_pv, *value_pv; pv_value_t uri_val, value_val, res_val; str uri, value; char *at, *colon, *c; char new_uri[MAX_URI_SIZE + 1]; uri_pv = (pv_spec_t *)_uri; if (uri_pv && (pv_get_spec_value(_m, uri_pv, &uri_val) == 0)) { if (uri_val.flags & PV_VAL_STR) { if (uri_val.rs.len == 0 || uri_val.rs.s == NULL) { LM_ERR("missing uri value\n"); return -1; } } else { LM_ERR("uri value is not string\n"); return -1; } } else { LM_ERR("failed to get uri value\n"); return -1; } uri = uri_val.rs; value_pv = (pv_spec_t *)_value; if (value_pv && (pv_get_spec_value(_m, value_pv, &value_val) == 0)) { if (value_val.flags & PV_VAL_STR) { if (value_val.rs.s == NULL) { LM_ERR("missing uriuser value\n"); return -1; } } else { LM_ERR("uriuser value is not string\n"); return -1; } } else { LM_ERR("failed to get uriuser value\n"); return -1; } value = value_val.rs; colon = strchr(uri.s, ':'); if (colon == NULL) { LM_ERR("uri does not contain ':' character\n"); return -1; } at = strchr(uri.s, '@'); c = &(new_uri[0]); if (at == NULL) { if (value.len == 0) return 1; if (uri.len + value.len > MAX_URI_SIZE) { LM_ERR("resulting uri would be too large\n"); return -1; } append_str(c, uri.s, colon - uri.s + 1); append_str(c, value.s, value.len); append_chr(c, '@'); append_str(c, colon + 1, uri.len - (colon - uri.s + 1)); res_val.rs.len = uri.len + value.len + 1; } else { if (value.len == 0) { append_str(c, uri.s, colon - uri.s + 1); append_str(c, at + 1, uri.len - (at - uri.s + 1)); res_val.rs.len = uri.len - (at - colon); } else { if (uri.len + value.len - (at - colon - 1) > MAX_URI_SIZE) { LM_ERR("resulting uri would be too large\n"); return -1; } append_str(c, uri.s, colon - uri.s + 1); append_str(c, value.s, value.len); append_str(c, at, uri.len - (at - uri.s)); res_val.rs.len = uri.len + value.len - (at - colon - 1); } } res_val.rs.s = &(new_uri[0]); LM_DBG("resulting uri: %.*s\n", res_val.rs.len, res_val.rs.s); res_val.flags = PV_VAL_STR; uri_pv->setf(_m, &uri_pv->pvp, (int)EQ_T, &res_val); return 1; }
/* * Converts URI, if it is tel URI, to SIP URI. Returns 1, if * conversion succeeded or if no conversion was needed, i.e., URI was not * tel URI. Returns -1, if conversion failed. Takes SIP URI hostpart from * second parameter and (if needed) writes the result to third paramater. */ int tel2sip(struct sip_msg* _msg, char* _uri, char* _hostpart, char* _res) { str uri, hostpart, tel_uri, sip_uri; char *at; int i, j, in_tel_parameters = 0; pv_spec_t *res; pv_value_t res_val; /* get parameters */ if (get_str_fparam(&uri, _msg, (fparam_t*)_uri) < 0) { LM_ERR("failed to get uri value\n"); } if (get_str_fparam(&hostpart, _msg, (fparam_t*)_hostpart) < 0) { LM_ERR("failed to get hostpart value\n"); } res = (pv_spec_t *)_res; /* check if anything needs to be done */ if (uri.len < 4) return 1; if (strncasecmp(uri.s, "tel:", 4) != 0) return 1; /* reserve memory for clean tel uri */ tel_uri.s = pkg_malloc(uri.len+1); if (tel_uri.s == 0) { LM_ERR("no more pkg memory\n"); return -1; } /* Remove visual separators before converting to SIP URI. Don't remove visual separators in TEL URI parameters (after the first ";") */ for (i=0, j=0; i < uri.len; i++) { if (in_tel_parameters == 0) { if (uri.s[i] == ';') in_tel_parameters = 1; } if (in_tel_parameters == 0) { if ((uri.s[i] != '-') && (uri.s[i] != '.') && (uri.s[i] != '(') && (uri.s[i] != ')')) tel_uri.s[j++] = tolower(uri.s[i]); } else { tel_uri.s[j++] = tolower(uri.s[i]); } } tel_uri.s[j] = '\0'; tel_uri.len = strlen(tel_uri.s); /* reserve memory for resulting sip uri */ sip_uri.len = 4 + tel_uri.len - 4 + 1 + hostpart.len + 1 + 10; sip_uri.s = pkg_malloc(sip_uri.len); if (sip_uri.s == 0) { LM_ERR("no more pkg memory\n"); pkg_free(tel_uri.s); return -1; } /* create resulting sip uri */ at = sip_uri.s; append_str(at, "sip:", 4); append_str(at, tel_uri.s + 4, tel_uri.len - 4); append_chr(at, '@'); append_str(at, hostpart.s, hostpart.len); append_chr(at, ';'); append_str(at, "user=phone", 10); /* tel_uri is not needed anymore */ pkg_free(tel_uri.s); /* set result pv value and write sip uri to result pv */ res_val.rs = sip_uri; res_val.flags = PV_VAL_STR; if (res->setf(_msg, &res->pvp, (int)EQ_T, &res_val) != 0) { LM_ERR("failed to set result pvar\n"); pkg_free(sip_uri.s); return -1; } /* free allocated pkg memory and return */ pkg_free(sip_uri.s); return 1; }
static int assemble_msg(struct sip_msg* msg, struct tw_info *twi) { static char id_buf[IDBUF_LEN]; static char route_buffer[ROUTE_BUFFER_MAX]; static char append_buf[APPEND_BUFFER_MAX]; static char cmd_buf[CMD_BUFFER_MAX]; static str empty_param = {".",1}; unsigned int hash_index, label; contact_body_t* cb=0; contact_t* c=0; name_addr_t na; rr_t* record_route; struct hdr_field* p_hdr; param_hooks_t hooks; int l; char* s, fproxy_lr; str route, next_hop, append, tmp_s, body, str_uri; if(msg->first_line.type != SIP_REQUEST){ LM_ERR("called for something else then a SIP request\n"); goto error; } /* parse all -- we will need every header field for a UAS */ if ( parse_headers(msg, HDR_EOH_F, 0)==-1) { LM_ERR("parse_headers failed\n"); goto error; } /* find index and hash; (the transaction can be safely used due * to refcounting till script completes) */ if( t_get_trans_ident(msg,&hash_index,&label) == -1 ) { LM_ERR("t_get_trans_ident failed\n"); goto error; } /* parse from header */ if (msg->from->parsed==0 && parse_from_header(msg)<0 ) { LM_ERR("failed to parse <From:> header\n"); goto error; } /* parse the RURI (doesn't make any malloc) */ msg->parsed_uri_ok = 0; /* force parsing */ if (parse_sip_msg_uri(msg)<0) { LM_ERR("uri has not been parsed\n"); goto error; } /* parse contact header */ str_uri.s = 0; str_uri.len = 0; if(msg->contact) { if (msg->contact->parsed==0 && parse_contact(msg->contact)<0) { LM_ERR("failed to parse <Contact:> header\n"); goto error; } cb = (contact_body_t*)msg->contact->parsed; if(cb && (c=cb->contacts)) { str_uri = c->uri; if (find_not_quoted(&str_uri,'<')) { parse_nameaddr(&str_uri,&na); str_uri = na.uri; } } } /* str_uri is taken from caller's contact or from header * for backwards compatibility with pre-3261 (from is already parsed)*/ if(!str_uri.len || !str_uri.s) str_uri = get_from(msg)->uri; /* parse Record-Route headers */ route.s = s = route_buffer; route.len = 0; fproxy_lr = 0; next_hop = empty_param; p_hdr = msg->record_route; if(p_hdr) { if (p_hdr->parsed==0 && parse_rr(p_hdr)!=0 ) { LM_ERR("failed to parse 'Record-Route:' header\n"); goto error; } record_route = (rr_t*)p_hdr->parsed; } else { record_route = 0; } if( record_route ) { if ( (tmp_s.s=find_not_quoted(&record_route->nameaddr.uri,';'))!=0 && tmp_s.s+1!=record_route->nameaddr.uri.s+ record_route->nameaddr.uri.len) { /* Parse all parameters */ tmp_s.len = record_route->nameaddr.uri.len - (tmp_s.s- record_route->nameaddr.uri.s); if (parse_params( &tmp_s, CLASS_URI, &hooks, &record_route->params) < 0) { LM_ERR("failed to parse record route uri params\n"); goto error; } fproxy_lr = (hooks.uri.lr != 0); LM_DBG("record_route->nameaddr.uri: %.*s\n", record_route->nameaddr.uri.len,record_route->nameaddr.uri.s); if(fproxy_lr){ LM_DBG("first proxy has loose routing\n"); copy_route(s,route.len,record_route->nameaddr.uri.s, record_route->nameaddr.uri.len); } } for(p_hdr = p_hdr->next;p_hdr;p_hdr = p_hdr->next) { /* filter out non-RR hdr and empty hdrs */ if( (p_hdr->type!=HDR_RECORDROUTE_T) || p_hdr->body.len==0) continue; if(p_hdr->parsed==0 && parse_rr(p_hdr)!=0 ){ LM_ERR("failed to parse <Record-route:> header\n"); goto error; } for(record_route=p_hdr->parsed; record_route; record_route=record_route->next){ LM_DBG("record_route->nameaddr.uri: <%.*s>\n", record_route->nameaddr.uri.len, record_route->nameaddr.uri.s); copy_route(s,route.len,record_route->nameaddr.uri.s, record_route->nameaddr.uri.len); } } if(!fproxy_lr){ copy_route(s,route.len,str_uri.s,str_uri.len); str_uri = ((rr_t*)msg->record_route->parsed)->nameaddr.uri; } else { next_hop = ((rr_t*)msg->record_route->parsed)->nameaddr.uri; } } LM_DBG("calculated route: %.*s\n",route.len,route.len ? route.s : ""); LM_DBG("next r-uri: %.*s\n",str_uri.len,str_uri.len ? str_uri.s : ""); if ( REQ_LINE(msg).method_value==METHOD_INVITE || (twi->append && twi->append->add_body) ) { /* get body */ if( (body.s = get_body(msg)) == 0 ){ LM_ERR("get_body failed\n"); goto error; } body.len = msg->len - (body.s - msg->buf); } else { body = empty_param; } /* flags & additional headers */ append.s = s = append_buf; if (sizeof(flag_t)*2+12+1 >= APPEND_BUFFER_MAX) { LM_ERR("buffer overflow while copying flags\n"); goto error; } append_str(s,"P-MsgFlags: ",12); l = APPEND_BUFFER_MAX - (12+1); /* include trailing `\n'*/ if (int2reverse_hex(&s, &l, (int)msg->msg_flags) == -1) { LM_ERR("buffer overflow while copying optional header\n"); goto error; } append_chr(s,'\n'); if ( twi->append && ((s=append2buf( s, APPEND_BUFFER_MAX-(s-append.s), msg, twi->append->elems))==0) ) goto error; /* body separator */ append_chr(s,'.'); append.len = s-append.s; eol_line(1).s = s = cmd_buf; if(twi->action.len+12 >= CMD_BUFFER_MAX){ LM_ERR("buffer overflow while copying command name\n"); goto error; } append_str(s,"sip_request.",12); append_str(s,twi->action.s,twi->action.len); eol_line(1).len = s-eol_line(1).s; eol_line(2)=REQ_LINE(msg).method; /* method type */ eol_line(3)=msg->parsed_uri.user; /* user from r-uri */ eol_line(4)=msg->parsed_uri.host; /* domain */ eol_line(5)=msg->rcv.bind_address->address_str; /* dst ip */ eol_line(6)=msg->rcv.dst_port==SIP_PORT ? empty_param : msg->rcv.bind_address->port_no_str; /* port */ /* r_uri ('Contact:' for next requests) */ eol_line(7)=*GET_RURI(msg); /* r_uri for subsequent requests */ eol_line(8)=str_uri.len?str_uri:empty_param; eol_line(9)=get_from(msg)->body; /* from */ eol_line(10)=msg->to->body; /* to */ eol_line(11)=msg->callid->body; /* callid */ eol_line(12)=get_from(msg)->tag_value; /* from tag */ eol_line(13)=get_to(msg)->tag_value; /* to tag */ eol_line(14)=get_cseq(msg)->number; /* cseq number */ eol_line(15).s=id_buf; /* hash:label */ s = int2str(hash_index, &l); if (l+1>=IDBUF_LEN) { LM_ERR("too big hash\n"); goto error; } memcpy(id_buf, s, l); id_buf[l]=':'; eol_line(15).len=l+1; s = int2str(label, &l); if (l+1+eol_line(15).len>=IDBUF_LEN) { LM_ERR("too big label\n"); goto error; } memcpy(id_buf+eol_line(15).len, s, l); eol_line(15).len+=l; eol_line(16) = route.len ? route : empty_param; eol_line(17) = next_hop; eol_line(18) = append; eol_line(19) = body; /* success */ return 1; error: /* 0 would lead to immediate script exit -- -1 returns * with 'false' to script processing */ return -1; }