int create_via(struct sip_msg* msg, char* s1, char* s2) { char* via; unsigned int via_len; str ip, port; struct hostport hp; struct dest_info dst; ip.s = ip_addr2a(&msg->rcv.src_ip); ip.len = strlen(ip.s); port.s = int2str(msg->rcv.src_port, &port.len); hp.host = &ip; hp.port = &port; init_dst_from_rcv(&dst, &msg->rcv); via = via_builder(&via_len, &dst, 0, 0, &hp); if (!via) { ERR("Unable to build Via header field\n"); return -1; } if (insert_fake_via(msg, via, via_len) < 0) { pkg_free(via); return -1; } if (insert_via_lump(msg, via, via_len - CRLF_LEN) < 0) { pkg_free(via); return -1; } return 1; }
/* * process_stun_msg(): * buf - incoming message * len - length of incoming message * ri - information about socket that received a message and * also information about sender (its IP, port, protocol) * * This function ensures processing of incoming message. It's common for both * TCP and UDP protocol. There is no other function as an interface. * * Return value: 0 if there is no environment error * -1 if there is some enviroment error such as insufficiency * of memory * */ int process_stun_msg(char* buf, unsigned len, struct receive_info* ri) { struct stun_msg msg_req; struct stun_msg msg_res; struct dest_info dst; struct stun_unknown_att* unknown; USHORT_T error_code; memset(&msg_req, 0, sizeof(msg_req)); memset(&msg_res, 0, sizeof(msg_res)); msg_req.msg.buf.s = buf; msg_req.msg.buf.len = len; unknown = NULL; error_code = RESPONSE_OK; if (stun_parse_header(&msg_req, &error_code) != 0) { goto error; } if (error_code == RESPONSE_OK) { if (stun_parse_body(&msg_req, &unknown, &error_code) != 0) { goto error; } } if (stun_create_response(&msg_req, &msg_res, ri, unknown, error_code) != 0) { goto error; } init_dst_from_rcv(&dst, ri); #ifdef EXTRA_DEBUG struct ip_addr ip; su2ip_addr(&ip, &dst.to); LOG(L_DBG, "DEBUG: process_stun_msg: decoded request from (%s:%d)\n", ip_addr2a(&ip), su_getport(&dst.to)); #endif /* send STUN response */ if (msg_send(&dst, msg_res.msg.buf.s, msg_res.msg.buf.len) != 0) { goto error; } #ifdef EXTRA_DEBUG LOG(L_DBG, "DEBUG: process_stun_msg: send response\n"); #endif clean_memory(&msg_req, &msg_res, unknown); return 0; error: #ifdef EXTRA_DEBUG LOG(L_DBG, "DEBUG: process_stun_msg: failed to decode request\n"); #endif clean_memory(&msg_req, &msg_res, unknown); return FATAL_ERROR; }
int tcp_http11_continue(struct tcp_connection *c) { struct dest_info dst; char *p; struct msg_start fline; int ret; str msg; ret = 0; msg.s = c->req.start; msg.len = c->req.pos - c->req.start; #ifdef READ_MSRP /* skip if MSRP message */ if(c->req.flags&F_TCP_REQ_MSRP_FRAME) return 0; #endif p = parse_first_line(msg.s, msg.len, &fline); if(p==NULL) return 0; if(fline.type!=SIP_REQUEST) return 0; /* check if http request */ if(fline.u.request.version.len < HTTP_VERSION_LEN || strncasecmp(fline.u.request.version.s, HTTP_VERSION, HTTP_VERSION_LEN)) return 0; /* check for Expect header */ if(strfindcasestrz(&msg, "Expect: 100-continue")!=NULL) { init_dst_from_rcv(&dst, &c->rcv); if (tcp_send(&dst, 0, HTTP11CONTINUE, HTTP11CONTINUE_LEN) < 0) { LM_ERR("HTTP/1.1 continue failed\n"); } } /* check for Transfer-Encoding header */ if(strfindcasestrz(&msg, "Transfer-Encoding: chunked")!=NULL) { c->req.flags |= F_TCP_REQ_BCHUNKED; ret = 1; } /* check for HTTP Via header * - HTTP Via format is different that SIP Via * - workaround: replace with Hia to be ignored by SIP parser */ if((p=strfindcasestrz(&msg, "\nVia:"))!=NULL) { p++; *p = 'H'; LM_DBG("replaced HTTP Via with Hia [[\n%.*s]]\n", msg.len, msg.s); } return ret; }
static char* xhttp_to_sip(sip_msg_t* msg, int* new_msg_len) { unsigned int len, via_len; char* via, *new_msg, *p; str ip, port; struct hostport hp; struct dest_info dst; ip.s = ip_addr2a(&msg->rcv.src_ip); ip.len = strlen(ip.s); port.s = int2str(msg->rcv.src_port, &port.len); hp.host = &ip; hp.port = &port; init_dst_from_rcv(&dst, &msg->rcv); via = via_builder(&via_len, &dst, 0, 0, &hp); if (via == 0) { LM_DBG("failed to build via\n"); return 0; } len = via_len + msg->len; p = new_msg = pkg_malloc(len + 1); if (new_msg == 0) { LM_DBG("memory allocation failure (%d bytes)\n", len); pkg_free(via); return 0; } /* new message: * <orig first line> * Via: <faked via> * <orig http message w/o the first line> */ memcpy(p, msg->first_line.u.request.method.s, msg->first_line.len); p += msg->first_line.len; memcpy(p, via, via_len); p += via_len; memcpy(p, SIP_MSG_START(msg) + msg->first_line.len, msg->len - msg->first_line.len); new_msg[len] = 0; pkg_free(via); *new_msg_len = len; return new_msg; }
/* * The function creates an ACK to 200 OK. Route set will be created * and parsed and the dst parameter will contain the destination to which * the request should be send. The function is used by tm when it * generates local ACK to 200 OK (on behalf of applications using uac) */ char *build_dlg_ack(struct sip_msg* rpl, struct cell *Trans, unsigned int branch, str *hdrs, str *body, unsigned int *len, struct dest_info* dst) { char *req_buf, *p, *via; unsigned int via_len; char branch_buf[MAX_BRANCH_PARAM_LEN]; int branch_len; str branch_str; struct hostport hp; struct rte* list; str contact, ruri, *cont; str next_hop; str body_len; str _to, *to = &_to; #ifdef USE_DNS_FAILOVER struct dns_srv_handle dns_h; #endif #ifdef WITH_AS_SUPPORT /* With AS support, TM allows for external modules to generate building of * the ACK; in this case, the ACK's retransmission buffer is built once * and kept in memory (to help when retransmitted 2xx are received and ACK * must be resent). * Allocation of the string raw buffer that holds the ACK is piggy-backed * with allocation of the retransmission buffer (since both have the same * life-cycle): both the string buffer and retransm. buffer are placed * into the same allocated chunk of memory (retr. buffer first, string * buffer follows).In this case, the 'len' param is used as in-out * parameter: 'in' to give the extra space needed by the retr. buffer, * 'out' to return the lenght of the allocated string buffer. */ unsigned offset = *len; #endif if (parse_headers(rpl, HDR_EOH_F, 0) == -1 || !rpl->to) { LM_ERR("Error while parsing headers.\n"); return 0; } else { _to.s = rpl->to->name.s; _to.len = rpl->to->len; } if (get_contact_uri(rpl, &contact) < 0) { return 0; } if (eval_uac_routing(rpl, &Trans->uac[branch].request, &contact, &list, &ruri, &next_hop) < 0) { LM_ERR("failed to evaluate routing elements.\n"); return 0; } LM_DBG("ACK RURI: `%.*s', NH: `%.*s'.\n", STR_FMT(&ruri), STR_FMT(&next_hop)); if ((contact.s != ruri.s) || (contact.len != ruri.len)) { /* contact != ruri means that the next * hop is a strict router, cont will be non-zero * and print_routeset will append it at the end * of the route set */ cont = &contact; } else { /* Next hop is a loose router, nothing to append */ cont = 0; } /* method, separators, version: "ACK sip:[email protected] SIP/2.0" */ *len = SIP_VERSION_LEN + ACK_LEN + 2 /* spaces */ + CRLF_LEN; *len += ruri.len; /* dst */ switch(cfg_get(tm, tm_cfg, local_ack_mode)){ case 1: /* send the local 200 ack to the same dst as the corresp. invite*/ *dst=Trans->uac[branch].request.dst; break; case 2: /* send the local 200 ack to the same dst as the 200 reply source*/ init_dst_from_rcv(dst, &rpl->rcv); dst->send_flags=rpl->fwd_send_flags; break; case 0: default: /* rfc conformant behaviour: use the next_hop determined from the * contact and the route set */ #ifdef USE_DNS_FAILOVER if (cfg_get(core, core_cfg, use_dns_failover)){ dns_srv_handle_init(&dns_h); if ((uri2dst(&dns_h , dst, rpl, &next_hop, PROTO_NONE)==0) || (dst->send_sock==0)){ dns_srv_handle_put(&dns_h); LM_ERR("no socket found\n"); goto error; } dns_srv_handle_put(&dns_h); /* not needed any more */ }else{ if ((uri2dst(0 , dst, rpl, &next_hop, PROTO_NONE)==0) || (dst->send_sock==0)){ LM_ERR("no socket found\n"); goto error; } } #else /* USE_DNS_FAILOVER */ if ( (uri2dst( dst, rpl, &next_hop, PROTO_NONE)==0) || (dst->send_sock==0)){ LM_ERR("no socket found\n"); goto error; } #endif /* USE_DNS_FAILOVER */ break; } /* via */ if (!t_calc_branch(Trans, branch, branch_buf, &branch_len)) goto error; branch_str.s = branch_buf; branch_str.len = branch_len; set_hostport(&hp, 0); via = via_builder(&via_len, NULL, dst, &branch_str, 0, &hp); if (!via) { LM_ERR("No via header got from builder\n"); goto error; } *len+= via_len; /* headers */ *len += Trans->from.len + Trans->callid.len + to->len + Trans->cseq_n.len + 1 + ACK_LEN + CRLF_LEN; /* copy'n'paste Route headers */ *len += calc_routeset_len(list, cont); /* User Agent */ if (server_signature) *len += user_agent_hdr.len + CRLF_LEN; /* extra headers */ if (hdrs) *len += hdrs->len; /* body */ if (body) { body_len.s = int2str(body->len, &body_len.len); *len += body->len; } else { body_len.len = 0; body_len.s = NULL; /*4gcc*/ *len += 1; /* for the (Cont-Len:) `0' */ } /* Content Length, EoM */ *len += CONTENT_LENGTH_LEN + body_len.len + CRLF_LEN + CRLF_LEN; #if WITH_AS_SUPPORT req_buf = shm_malloc(offset + *len + 1); req_buf += offset; #else req_buf = shm_malloc(*len + 1); #endif if (!req_buf) { LM_ERR("Cannot allocate memory (%u+1)\n", *len); goto error01; } p = req_buf; append_str( p, ACK, ACK_LEN ); append_str( p, " ", 1 ); append_str(p, ruri.s, ruri.len); append_str( p, " " SIP_VERSION CRLF, 1 + SIP_VERSION_LEN + CRLF_LEN); /* insert our via */ append_str(p, via, via_len); /*other headers*/ append_str(p, Trans->from.s, Trans->from.len); append_str(p, Trans->callid.s, Trans->callid.len); append_str(p, to->s, to->len); append_str(p, Trans->cseq_n.s, Trans->cseq_n.len); append_str( p, " ", 1 ); append_str( p, ACK, ACK_LEN); append_str(p, CRLF, CRLF_LEN); /* Routeset */ p = print_rs(p, list, cont); /* User Agent header */ if (server_signature) { append_str(p, user_agent_hdr.s, user_agent_hdr.len); append_str(p, CRLF, CRLF_LEN); } /* extra headers */ if (hdrs) append_str(p, hdrs->s, hdrs->len); /* Content Length, EoH, (body) */ if (body) { append_str(p, CONTENT_LENGTH, CONTENT_LENGTH_LEN); append_str(p, body_len.s, body_len.len); append_str(p, /*end crr. header*/CRLF /*EoH*/CRLF, CRLF_LEN + CRLF_LEN); append_str(p, body->s, body->len); } else { append_str(p, CONTENT_LENGTH "0" CRLF CRLF, CONTENT_LENGTH_LEN + 1 + CRLF_LEN + CRLF_LEN); } /* EoM */ *p = 0; pkg_free(via); free_rte_list(list); return req_buf; error01: pkg_free(via); error: free_rte_list(list); return 0; }
int tcp_read_req(struct tcp_connection* con, int* bytes_read, int* read_flags) { int bytes; int total_bytes; int resp; long size; struct tcp_req* req; struct dest_info dst; char c; int ret; bytes=-1; total_bytes=0; resp=CONN_RELEASE; req=&con->req; again: if (likely(req->error==TCP_REQ_OK)){ #ifdef READ_WS if (unlikely(con->type == PROTO_WS || con->type == PROTO_WSS)) bytes=tcp_read_ws(con, read_flags); else #endif bytes=tcp_read_headers(con, read_flags); #ifdef EXTRA_DEBUG /* if timeout state=0; goto end__req; */ LM_DBG("read= %d bytes, parsed=%d, state=%d, error=%d\n", bytes, (int)(req->parsed-req->start), req->state, req->error ); LM_DBG("last char=0x%02X, parsed msg=\n%.*s\n", *(req->parsed-1), (int)(req->parsed-req->start), req->start); #endif if (unlikely(bytes==-1)){ LOG(cfg_get(core, core_cfg, corelog), "ERROR: tcp_read_req: error reading \n"); resp=CONN_ERROR; goto end_req; } total_bytes+=bytes; /* eof check: * is EOF if eof on fd and req. not complete yet, * if req. is complete we might have a second unparsed * request after it, so postpone release_with_eof */ if (unlikely((con->state==S_CONN_EOF) && (! TCP_REQ_COMPLETE(req)))) { LM_DBG("EOF\n"); resp=CONN_EOF; goto end_req; } } if (unlikely(req->error!=TCP_REQ_OK)){ LM_ERR("bad request, state=%d, error=%d buf:\n%.*s\nparsed:\n%.*s\n", req->state, req->error, (int)(req->pos-req->buf), req->buf, (int)(req->parsed-req->start), req->start); LM_DBG("received from: port %d\n", con->rcv.src_port); print_ip("received from: ip", &con->rcv.src_ip, "\n"); resp=CONN_ERROR; goto end_req; } if (likely(TCP_REQ_COMPLETE(req))){ #ifdef EXTRA_DEBUG LM_DBG("end of header part\n"); LM_DBG("received from: port %d\n", con->rcv.src_port); print_ip("received from: ip", &con->rcv.src_ip, "\n"); LM_DBG("headers:\n%.*s.\n", (int)(req->body-req->start), req->start); #endif if (likely(TCP_REQ_HAS_CLEN(req))){ LM_DBG("content-length=%d\n", req->content_len); #ifdef EXTRA_DEBUG LM_DBG("body:\n%.*s\n", req->content_len,req->body); #endif }else{ if (cfg_get(tcp, tcp_cfg, accept_no_cl)==0) { req->error=TCP_REQ_BAD_LEN; LM_ERR("content length not present or unparsable\n"); resp=CONN_ERROR; goto end_req; } } /* if we are here everything is nice and ok*/ resp=CONN_RELEASE; #ifdef EXTRA_DEBUG LM_DBG("receiving msg(%p, %d)\n", req->start, (int)(req->parsed-req->start)); #endif /* rcv.bind_address should always be !=0 */ bind_address=con->rcv.bind_address; /* just for debugging use sendipv4 as receiving socket FIXME*/ /* if (con->rcv.dst_ip.af==AF_INET6){ bind_address=sendipv6_tcp; }else{ bind_address=sendipv4_tcp; } */ con->rcv.proto_reserved1=con->id; /* copy the id */ c=*req->parsed; /* ugly hack: zero term the msg & save the previous char, req->parsed should be ok because we always alloc BUF_SIZE+1 */ *req->parsed=0; if (req->state==H_PING_CRLF) { init_dst_from_rcv(&dst, &con->rcv); if (tcp_send(&dst, 0, CRLF, CRLF_LEN) < 0) { LM_ERR("CRLF ping: tcp_send() failed\n"); } ret = 0; } else if (unlikely(req->state==H_STUN_END)) { /* stun request */ ret = stun_process_msg(req->start, req->parsed-req->start, &con->rcv); } else #ifdef READ_MSRP // if (unlikely(req->flags&F_TCP_REQ_MSRP_FRAME)){ if (unlikely(req->state==H_MSRP_FINISH)){ /* msrp frame */ ret = receive_tcp_msg(req->start, req->parsed-req->start, &con->rcv, con); }else #endif #ifdef READ_HTTP11 if (unlikely(req->state==H_HTTP11_CHUNK_FINISH)){ /* http chunked request */ req->body[req->content_len] = 0; ret = receive_tcp_msg(req->start, req->body + req->content_len - req->start, &con->rcv, con); }else #endif #ifdef READ_WS if (unlikely(con->type == PROTO_WS || con->type == PROTO_WSS)){ ret = receive_tcp_msg(req->start, req->parsed-req->start, &con->rcv, con); }else #endif ret = receive_tcp_msg(req->start, req->parsed-req->start, &con->rcv, con); if (unlikely(ret < 0)) { *req->parsed=c; resp=CONN_ERROR; goto end_req; } *req->parsed=c; /* prepare for next request */ size=req->pos-req->parsed; req->start=req->buf; req->body=0; req->error=TCP_REQ_OK; req->state=H_SKIP_EMPTY; req->flags=0; req->content_len=0; req->bytes_to_go=0; req->pos=req->buf+size; if (unlikely(size)){ memmove(req->buf, req->parsed, size); req->parsed=req->buf; /* fix req->parsed after using it */ #ifdef EXTRA_DEBUG LM_DBG("preparing for new request, kept %ld bytes\n", size); #endif /*if we still have some unparsed bytes, try to parse them too*/ goto again; } else if (unlikely(con->state==S_CONN_EOF)){ LM_DBG("EOF after reading complete request\n"); resp=CONN_EOF; } req->parsed=req->buf; /* fix req->parsed */ } end_req: if (likely(bytes_read)) *bytes_read=total_bytes; return resp; }