static int set_destination(struct sip_msg* msg, str* dest) { name_addr_t nameaddr; if (!parse_nameaddr(dest, &nameaddr)) { return set_dst_uri(msg, &nameaddr.uri); } else { /* it is just URI, pass it through */ return set_dst_uri(msg, dest); } }
int parse_first_nameaddr(sip_nameaddr* na, const char* c, int len) { const char* tmp_c = c; const char* end = c + len; const char* na_end = NULL; const char* na_begin = c; int err = skip_2_next_nameaddr(tmp_c,na_end,end); if(err < 0){ ERROR("While parsing first nameaddr ('%.*s')\n",len,c); return -1; } tmp_c = c; return parse_nameaddr(na,&tmp_c,na_end-tmp_c); }
int parse_nameaddr_uri(sip_nameaddr* na, const char** c, int len) { if(parse_nameaddr(na, c, len) < 0) { DBG("Parsing name-addr failed\n"); return -1; } if(parse_uri(&na->uri,na->addr.s,na->addr.len) < 0) { DBG("Parsing uri failed\n"); return -1; } return 0; }
/* * Check if URI in RPID AVP contains an E164 user part */ int is_rpid_user_e164(struct sip_msg* _m, char* _s1, char* _s2) { struct usr_avp *avp; name_addr_t parsed; str tmp, rpid; struct sip_uri uri; int_str val; if (rpid_avp_name==-1) { LM_ERR("rpid avp not defined\n"); return -1; } if ( (avp=search_first_avp( rpid_avp_type , rpid_avp_name, &val, 0))==0 ) { LM_DBG("no rpid AVP\n"); goto err; } if ( !(avp->flags&AVP_VAL_STR) || !val.s.s || !val.s.len) { LM_DBG("empty or non-string rpid, nothing to append\n"); return -1; } rpid = val.s; if (find_not_quoted(&rpid, '<')) { if (parse_nameaddr(&rpid, &parsed) < 0) { LM_ERR("failed to parse RPID\n"); goto err; } tmp = parsed.uri; } else { tmp = rpid; } if (parse_uri(tmp.s, tmp.len, &uri) < 0) { LM_ERR("failed to parse RPID URI\n"); goto err; } return is_e164(&uri.user); err: return -1; }
/*! \brief * Parse Route or Record-Route body */ static inline int do_parse_rr_body(char *buf, int len, rr_t **head) { rr_t* r, *last; str s; param_hooks_t hooks; /* Make a temporary copy of the string pointer */ if(buf==0 || len<=0) { DBG("parse_rr_body(): No body for record-route\n"); *head = 0; return -2; } s.s = buf; s.len = len; trim_leading(&s); last = 0; while(1) { /* Allocate and clear rr structure */ r = (rr_t*)pkg_malloc(sizeof(rr_t)); if (!r) { LOG(L_ERR, "parse_rr(): No memory left\n"); goto error; } memset(r, 0, sizeof(rr_t)); /* Parse name-addr part of the header */ if (parse_nameaddr(&s, &r->nameaddr) < 0) { LOG(L_ERR, "parse_rr(): Error while parsing name-addr (%.*s)\n", s.len, ZSW(s.s)); goto error; } r->len = r->nameaddr.len; /* Shift just behind the closing > */ s.s = r->nameaddr.name.s + r->nameaddr.len; /* Point just behind > */ s.len -= r->nameaddr.len; trim_leading(&s); /* Skip any white-chars */ if (s.len == 0) goto ok; /* Nothing left, finish */ if (s.s[0] == ';') { /* Route parameter found */ s.s++; s.len--; trim_leading(&s); if (s.len == 0) { LOG(L_ERR, "parse_rr(): Error while parsing params\n"); goto error; } /* Parse all parameters */ if (parse_params(&s, CLASS_ANY, &hooks, &r->params) < 0) { LOG(L_ERR, "parse_rr(): Error while parsing params\n"); goto error; } r->len = r->params->name.s + r->params->len - r->nameaddr.name.s; /* Copy hooks */ /*r->r2 = hooks.rr.r2; */ trim_leading(&s); if (s.len == 0) goto ok; } if (s.s[0] != ',') { LOG(L_ERR, "parse_rr(): Invalid character '%c', comma expected\n", s.s[0]); goto error; } /* Next character is comma or end of header*/ s.s++; s.len--; trim_leading(&s); if (s.len == 0) { LOG(L_ERR, "parse_rr(): Text after comma missing\n"); goto error; } /* Append the structure as last parameter of the linked list */ if (!*head) *head = r; if (last) last->next = r; last = r; } error: if (r) free_rr(&r); free_rr(head); /* Free any contacts created so far */ return -1; ok: if (!*head) *head = r; if (last) last->next = r; return 0; }
/* * Parse Route and Record-Route header fields */ int parse_rr(struct hdr_field* _h) { rr_t* r, *last; str s; param_hooks_t hooks; if (!_h) { LOG(L_ERR, "parse_rr(): Invalid parameter value\n"); return -1; } if (_h->parsed) { /* Already parsed, return */ return 0; } /* Make a temporary copy of the string pointer */ s.s = _h->body.s; s.len = _h->body.len; trim_leading(&s); last = 0; while(1) { /* Allocate and clear rr stucture */ r = (rr_t*)pkg_malloc(sizeof(rr_t)); if (!r) { LOG(L_ERR, "parse_rr(): No memory left\n"); goto error; } memset(r, 0, sizeof(rr_t)); /* Parse name-addr part of the header */ if (parse_nameaddr(&s, &r->nameaddr) < 0) { LOG(L_ERR, "parse_rr(): Error while parsing name-addr\n"); goto error; } r->len = r->nameaddr.len; /* Shift just behind the closing > */ s.s = r->nameaddr.name.s + r->nameaddr.len; /* Point just behind > */ s.len -= r->nameaddr.len; trim_leading(&s); /* Skip any whitechars */ /* Nothing left, finish */ if (s.len == 0) goto ok; if (s.s[0] == ';') { /* Contact parameter found */ s.s++; s.len--; trim_leading(&s); if (s.len == 0) { LOG(L_ERR, "parse_rr(): Error while parsing params\n"); goto error; } /* Parse all parameters */ if (parse_params(&s, CLASS_ANY, &hooks, &r->params) < 0) { LOG(L_ERR, "parse_rr(): Error while parsing params\n"); goto error; } r->len = r->params->name.s + r->params->len - r->nameaddr.name.s; /* Copy hooks */ /*r->r2 = hooks.rr.r2; */ trim_leading(&s); if (s.len == 0) goto ok; } if (s.s[0] != ',') { LOG(L_ERR, "parse_rr(): Invalid character '%c', comma expected\n", s.s[0]); goto error; } /* Next character is comma or end of header*/ s.s++; s.len--; trim_leading(&s); if (s.len == 0) { LOG(L_ERR, "parse_rr(): Text after comma missing\n"); goto error; } /* Append the structure as last parameter of the linked list */ if (!_h->parsed) _h->parsed = (void*)r; if (last) last->next = r; last = r; } error: if (r) pkg_free(r); free_rr((rr_t**)&_h->parsed); /* Free any contacts created so far */ return -1; ok: if (!_h->parsed) _h->parsed = (void*)r; if (last) last->next = r; return 0; }
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; }
// // Ref. RFC 3261 "12.2.1.1 Generating the Request" // int trans_layer::set_next_hop(list<sip_header*>& route_hdrs, cstring& r_uri, sockaddr_storage* remote_ip) { string next_hop; unsigned short next_port=0; //assert(msg->type == SIP_REQUEST); int err=0; if(!route_hdrs.empty()){ sip_header* fr = route_hdrs.front(); sip_nameaddr na; const char* c = fr->value.s; if(parse_nameaddr(&na, &c, fr->value.len)<0) { DBG("Parsing name-addr failed\n"); return -1; } if(parse_uri(&na.uri,na.addr.s,na.addr.len) < 0) { DBG("Parsing route uri failed\n"); return -1; } bool is_lr = false; if(!na.uri.params.empty()){ list<sip_avp*>::iterator it = na.uri.params.begin(); for(;it != na.uri.params.end(); it++){ if( ((*it)->name.len == 2) && (!memcmp((*it)->name.s,"lr",2)) ) { is_lr = true; break; } } } if (SipCtrlInterfaceFactory::outbound_host.empty()) { next_hop = c2stlstr(na.uri.host); next_port = na.uri.port; } else { next_hop = SipCtrlInterfaceFactory::outbound_host; next_port = SipCtrlInterfaceFactory::outbound_port; } if(!is_lr){ // detect beginning of next route enum { RR_PARAMS=0, RR_QUOTED, RR_SEP_SWS, // space(s) after ',' RR_NXT_ROUTE }; int st = RR_PARAMS; const char* end = fr->value.s + fr->value.len; for(;c<end;c++){ switch(st){ case RR_PARAMS: switch(*c){ case SP: case HTAB: case CR: case LF: break; case COMMA: st = RR_SEP_SWS; break; case DQUOTE: st = RR_QUOTED; break; } break; case RR_QUOTED: switch(*c){ case BACKSLASH: c++; break; case DQUOTE: st = RR_PARAMS; break; } break; case RR_SEP_SWS: switch(*c){ case SP: case HTAB: case CR: case LF: break; default: st = RR_NXT_ROUTE; goto nxt_route; } break; } } nxt_route: switch(st){ case RR_QUOTED: case RR_SEP_SWS: DBG("Malformed first route header\n"); case RR_PARAMS: // remove current route header from message DBG("delete (fr=0x%p)\n",fr); delete fr; // route_hdrs.front(); route_hdrs.pop_front(); DBG("route_hdrs.length() = %i\n",(int)route_hdrs.size()); break; case RR_NXT_ROUTE: // remove current route from this header fr->value.s = c; fr->value.len = end-c; break; } // copy r_uri at the end of // the route set. route_hdrs.push_back(new sip_header(0,"Route",r_uri)); r_uri = na.addr; } } else { if (SipCtrlInterfaceFactory::outbound_host.empty()) { sip_uri parsed_r_uri; err = parse_uri(&parsed_r_uri,r_uri.s,r_uri.len); if(err < 0){ ERROR("Invalid Request URI\n"); return -1; } next_hop = c2stlstr(parsed_r_uri.host); next_port = parsed_r_uri.port; } else { next_hop = SipCtrlInterfaceFactory::outbound_host; next_port = SipCtrlInterfaceFactory::outbound_port; } } DBG("next_hop:next_port is <%s:%u>\n", next_hop.c_str(), next_port); err = resolver::instance()->resolve_name(next_hop.c_str(), remote_ip,IPv4,UDP); if(err < 0){ ERROR("Unresolvable Request URI\n"); return -1; } ((sockaddr_in*)remote_ip)->sin_port = htons(next_port); return 0; }
void trans_layer::send_200_ack(sip_msg* reply, sip_trans* t) { // Set request URI // TODO: use correct R-URI instead of just 'Contact' if(!get_contact(reply)) { DBG("Sorry, reply has no Contact header: could not send ACK\n"); return; } sip_nameaddr na; const char* c = get_contact(reply)->value.s; if(parse_nameaddr(&na,&c,get_contact(reply)->value.len) < 0){ DBG("Sorry, reply's Contact parsing failed: could not send ACK\n"); return; } cstring r_uri = na.addr; list<sip_header*> route_hdrs; if(t && !t->msg->route.empty()){ for(list<sip_header*>::iterator it = t->msg->route.begin(); it != t->msg->route.end(); ++it) { route_hdrs.push_back(new sip_header(0,"Route",(*it)->value)); } } else { for(list<sip_header*>::reverse_iterator it = reply->record_route.rbegin(); it != reply->record_route.rend(); ++it) { route_hdrs.push_back(new sip_header(0,"Route",(*it)->value)); } } sockaddr_storage remote_ip; set_next_hop(route_hdrs,r_uri,&remote_ip); int request_len = request_line_len(cstring("ACK",3),r_uri); char branch_buf[BRANCH_BUF_LEN]; compute_branch(branch_buf,reply->callid->value,reply->cseq->value); cstring branch(branch_buf,BRANCH_BUF_LEN); sip_header* max_forward = new sip_header(0,cstring("Max-Forwards"),cstring("10")); cstring via((char*)transport->get_local_ip()); request_len += via_len(via,branch); request_len += copy_hdrs_len(route_hdrs); request_len += copy_hdr_len(reply->to); request_len += copy_hdr_len(reply->from); request_len += copy_hdr_len(reply->callid); request_len += copy_hdr_len(max_forward); request_len += cseq_len(get_cseq(reply)->num_str,cstring("ACK",3)); request_len += 2/* CRLF end-of-headers*/; // Allocate new message char* ack_buf = new char[request_len]; // generate it char* msg = ack_buf; request_line_wr(&msg,cstring("ACK",3),r_uri); via_wr(&msg,via,branch); copy_hdrs_wr(&msg,route_hdrs); // clear route headers list for (list<sip_header*>::iterator it=route_hdrs.begin(); it!= route_hdrs.end(); it++) delete *it; copy_hdr_wr(&msg,reply->from); copy_hdr_wr(&msg,reply->to); copy_hdr_wr(&msg,reply->callid); copy_hdr_wr(&msg,max_forward); delete max_forward; cseq_wr(&msg,get_cseq(reply)->num_str,cstring("ACK",3)); *msg++ = CR; *msg++ = LF; DBG("About to send 200 ACK\n"); // DBG("About to send 200 ACK: \n<%.*s>\n",request_len,ack_buf); assert(transport); int send_err = transport->send(&remote_ip,ack_buf,request_len); if(send_err < 0){ ERROR("Error from transport layer\n"); delete [] ack_buf; } else if(t){ delete [] t->retr_buf; t->retr_buf = ack_buf; t->retr_len = request_len; memcpy(&t->retr_addr,&remote_ip,sizeof(sockaddr_storage)); } }
int parse_from_to(sip_from_to* ft, const char* beg, int len) { enum { FTP_BEG, FTP_TAG1, FTP_TAG2, FTP_TAG3, FTP_OTHER }; const char* c = beg; const char* end = c+len; int ret = parse_nameaddr(&ft->nameaddr,&c,len); if(ret) return ret; ret = parse_gen_params(&ft->params,&c, end-c, 0); if(!ft->params.empty()){ list<sip_avp*>::iterator it = ft->params.begin(); for(;it!=ft->params.end();++it){ const char* c = (*it)->name.s; const char* end = c + (*it)->name.len; int st = FTP_BEG; for(;c!=end;c++){ #define case_FT_PARAM(st1,ch1,ch2,st2)\ case st1:\ switch(*c){\ case ch1:\ case ch2:\ st = st2;\ break;\ default:\ st = FTP_OTHER;\ }\ break switch(st){ case_FT_PARAM(FTP_BEG, 't','T',FTP_TAG1); case_FT_PARAM(FTP_TAG1,'a','A',FTP_TAG2); case_FT_PARAM(FTP_TAG2,'g','G',FTP_TAG3); case FTP_OTHER: goto next_param; } } switch(st){ case FTP_TAG3: ft->tag = (*it)->value; break; } next_param: continue; } } return ret; }