From e30a355397b285a5140ebb25a485bed7134de7ee Mon Sep 17 00:00:00 2001 From: Vlad Paiu Date: Mon, 30 Oct 2023 13:46:43 +0200 Subject: [PATCH] Support overlapping SIP&HTTP headers in WS HTTP initial requests --- modules/proto_ws/ws_handshake_common.h | 4 +- parser/msg_parser.c | 260 ++++++++++++++++--------- parser/msg_parser.h | 8 +- 3 files changed, 180 insertions(+), 92 deletions(-) diff --git a/modules/proto_ws/ws_handshake_common.h b/modules/proto_ws/ws_handshake_common.h index 592ef06d553..1d961347696 100644 --- a/modules/proto_ws/ws_handshake_common.h +++ b/modules/proto_ws/ws_handshake_common.h @@ -844,7 +844,7 @@ static int ws_parse_req_handshake(struct tcp_connection *c, char *msg, int len) memset(&tmp_msg, 0, sizeof(struct sip_msg)); tmp_msg.len = len; tmp_msg.buf = tmp_msg.unparsed = msg; - if (parse_headers(&tmp_msg, HDR_EOH_F, 0) < 0) { + if (parse_headers_aux(&tmp_msg, HDR_EOH_F, 0,0) < 0) { LM_ERR("cannot parse headers\n%.*s\n", len, msg); goto error; } @@ -1122,7 +1122,7 @@ static int ws_parse_rpl_handshake(struct tcp_connection *c, char *msg, int len) memset(&tmp_msg, 0, sizeof(struct sip_msg)); tmp_msg.len = len; tmp_msg.buf = tmp_msg.unparsed = msg; - if (parse_headers(&tmp_msg, HDR_EOH_F, 0) < 0) { + if (parse_headers_aux(&tmp_msg, HDR_EOH_F, 0, 0) < 0) { LM_ERR("cannot parse headers\n%.*s\n", len, msg); goto error; } diff --git a/parser/msg_parser.c b/parser/msg_parser.c index f32f4e928e7..9ffdfe5e97b 100644 --- a/parser/msg_parser.c +++ b/parser/msg_parser.c @@ -68,7 +68,7 @@ int via_cnt; /* returns pointer to next header line, and fill hdr_f ; * if at end of header returns pointer to the last crlf (always buf)*/ -char* get_hdr_field(char* buf, char* end, struct hdr_field* hdr) +char* get_hdr_field_aux(char* buf, char* end, struct hdr_field* hdr,int sip_well_known_parse) { char* tmp; @@ -107,88 +107,172 @@ char* get_hdr_field(char* buf, char* end, struct hdr_field* hdr) /* keep number of vias parsed -- we want to report it in replies for diagnostic purposes */ via_cnt++; - vb=pkg_malloc(sizeof(struct via_body)); - if (vb==0){ - LM_ERR("out of pkg memory\n"); - goto error; - } - memset(vb,0,sizeof(struct via_body)); - hdr->body.s=tmp; - tmp=parse_via(tmp, end, vb); - if (vb->error==PARSE_ERROR){ - LM_ERR("bad via\n"); - free_via_list(vb); - set_err_info(OSER_EC_PARSER, OSER_EL_MEDIUM, - "error parsing Via"); - set_err_reply(400, "bad Via header"); - goto error; + if (sip_well_known_parse) { + vb=pkg_malloc(sizeof(struct via_body)); + if (vb==0){ + LM_ERR("out of pkg memory\n"); + goto error; + } + memset(vb,0,sizeof(struct via_body)); + hdr->body.s=tmp; + tmp=parse_via(tmp, end, vb); + if (vb->error==PARSE_ERROR){ + LM_ERR("bad via\n"); + free_via_list(vb); + set_err_info(OSER_EC_PARSER, OSER_EL_MEDIUM, + "error parsing Via"); + set_err_reply(400, "bad Via header"); + goto error; + } + hdr->parsed=vb; + vb->hdr.s=hdr->name.s; + vb->hdr.len=hdr->name.len; + hdr->body.len=tmp-hdr->body.s; + } else { + /* just skip over it */ + hdr->body.s=tmp; + /* find end of header */ + /* find lf */ + do{ + match=q_memchr(tmp, '\n', end-tmp); + if (match){ + match++; + }else { + LM_ERR("bad body for <%.*s>(%d)\n", + hdr->name.len, hdr->name.s, hdr->type); + tmp=end; + goto error_bad_hdr; + } + tmp=match; + }while( matchbody.len=match-hdr->body.s; } - hdr->parsed=vb; - vb->hdr.s=hdr->name.s; - vb->hdr.len=hdr->name.len; - hdr->body.len=tmp-hdr->body.s; break; case HDR_CSEQ_T: - cseq_b=pkg_malloc(sizeof(struct cseq_body)); - if (cseq_b==0){ - LM_ERR("out of pkg memory\n"); - goto error; - } - memset(cseq_b, 0, sizeof(struct cseq_body)); - hdr->body.s=tmp; - tmp=parse_cseq(tmp, end, cseq_b); - if (cseq_b->error==PARSE_ERROR){ - LM_ERR("bad cseq\n"); - pkg_free(cseq_b); - set_err_info(OSER_EC_PARSER, OSER_EL_MEDIUM, - "error parsing CSeq`"); - set_err_reply(400, "bad CSeq header"); - goto error; + if (sip_well_known_parse) { + cseq_b=pkg_malloc(sizeof(struct cseq_body)); + if (cseq_b==0){ + LM_ERR("out of pkg memory\n"); + goto error; + } + memset(cseq_b, 0, sizeof(struct cseq_body)); + hdr->body.s=tmp; + tmp=parse_cseq(tmp, end, cseq_b); + if (cseq_b->error==PARSE_ERROR){ + LM_ERR("bad cseq\n"); + pkg_free(cseq_b); + set_err_info(OSER_EC_PARSER, OSER_EL_MEDIUM, + "error parsing CSeq`"); + set_err_reply(400, "bad CSeq header"); + goto error; + } + hdr->parsed=cseq_b; + hdr->body.len=tmp-hdr->body.s; + LM_DBG("cseq <%.*s>: <%.*s> <%.*s>\n", + hdr->name.len, ZSW(hdr->name.s), + cseq_b->number.len, ZSW(cseq_b->number.s), + cseq_b->method.len, cseq_b->method.s); + } else { + /* just skip over it */ + hdr->body.s=tmp; + /* find end of header */ + /* find lf */ + do{ + match=q_memchr(tmp, '\n', end-tmp); + if (match){ + match++; + }else { + LM_ERR("bad body for <%.*s>(%d)\n", + hdr->name.len, hdr->name.s, hdr->type); + tmp=end; + goto error_bad_hdr; + } + tmp=match; + }while( matchbody.len=match-hdr->body.s; } - hdr->parsed=cseq_b; - hdr->body.len=tmp-hdr->body.s; - LM_DBG("cseq <%.*s>: <%.*s> <%.*s>\n", - hdr->name.len, ZSW(hdr->name.s), - cseq_b->number.len, ZSW(cseq_b->number.s), - cseq_b->method.len, cseq_b->method.s); break; case HDR_TO_T: - to_b=pkg_malloc(sizeof(struct to_body)); - if (to_b==0){ - LM_ERR("out of pkg memory\n"); - goto error; - } - memset(to_b, 0, sizeof(struct to_body)); - hdr->body.s=tmp; - tmp=parse_to(tmp, end,to_b); - if (to_b->error==PARSE_ERROR){ - LM_ERR("bad to header\n"); - pkg_free(to_b); - set_err_info(OSER_EC_PARSER, OSER_EL_MEDIUM, - "error parsing To header"); - set_err_reply(400, "bad header"); - goto error; + if (sip_well_known_parse) { + to_b=pkg_malloc(sizeof(struct to_body)); + if (to_b==0){ + LM_ERR("out of pkg memory\n"); + goto error; + } + memset(to_b, 0, sizeof(struct to_body)); + hdr->body.s=tmp; + tmp=parse_to(tmp, end,to_b); + if (to_b->error==PARSE_ERROR){ + LM_ERR("bad to header\n"); + pkg_free(to_b); + set_err_info(OSER_EC_PARSER, OSER_EL_MEDIUM, + "error parsing To header"); + set_err_reply(400, "bad header"); + goto error; + } + hdr->parsed=to_b; + hdr->body.len=tmp-hdr->body.s; + LM_DBG("<%.*s> [%d]; uri=[%.*s] \n", + hdr->name.len, ZSW(hdr->name.s), + hdr->body.len, to_b->uri.len,ZSW(to_b->uri.s)); + LM_DBG("to body [%.*s]\n",to_b->body.len, ZSW(to_b->body.s)); + } else { + /* just skip over it */ + hdr->body.s=tmp; + /* find end of header */ + /* find lf */ + do{ + match=q_memchr(tmp, '\n', end-tmp); + if (match){ + match++; + }else { + LM_ERR("bad body for <%.*s>(%d)\n", + hdr->name.len, hdr->name.s, hdr->type); + tmp=end; + goto error_bad_hdr; + } + tmp=match; + }while( matchbody.len=match-hdr->body.s; } - hdr->parsed=to_b; - hdr->body.len=tmp-hdr->body.s; - LM_DBG("<%.*s> [%d]; uri=[%.*s] \n", - hdr->name.len, ZSW(hdr->name.s), - hdr->body.len, to_b->uri.len,ZSW(to_b->uri.s)); - LM_DBG("to body [%.*s]\n",to_b->body.len, ZSW(to_b->body.s)); break; case HDR_CONTENTLENGTH_T: - hdr->body.s=tmp; - tmp=parse_content_length(tmp,end, &integer); - if (tmp==0){ - LM_ERR("bad content_length header\n"); - set_err_info(OSER_EC_PARSER, OSER_EL_MEDIUM, - "error parsing Content-Length"); - set_err_reply(400, "bad Content-Length header"); - goto error; + if (sip_well_known_parse) { + hdr->body.s=tmp; + tmp=parse_content_length(tmp,end, &integer); + if (tmp==0){ + LM_ERR("bad content_length header\n"); + set_err_info(OSER_EC_PARSER, OSER_EL_MEDIUM, + "error parsing Content-Length"); + set_err_reply(400, "bad Content-Length header"); + goto error; + } + hdr->parsed=(void*)(long)integer; + hdr->body.len=tmp-hdr->body.s; + LM_DBG("content_length=%d\n", (int)(long)hdr->parsed); + } else { + /* just skip over it */ + hdr->body.s=tmp; + /* find end of header */ + /* find lf */ + do{ + match=q_memchr(tmp, '\n', end-tmp); + if (match){ + match++; + }else { + LM_ERR("bad body for <%.*s>(%d)\n", + hdr->name.len, hdr->name.s, hdr->type); + tmp=end; + goto error_bad_hdr; + } + tmp=match; + }while( matchbody.len=match-hdr->body.s; } - hdr->parsed=(void*)(long)integer; - hdr->body.len=tmp-hdr->body.s; - LM_DBG("content_length=%d\n", (int)(long)hdr->parsed); break; case HDR_SUPPORTED_T: case HDR_CONTENTTYPE_T: @@ -278,8 +362,6 @@ char* get_hdr_field(char* buf, char* end, struct hdr_field* hdr) return tmp; } - - /* parse the headers and adds them to msg->headers and msg->to, from etc. * It stops when all the headers requested in flags were parsed, on error * (bad header) or end of headers */ @@ -292,7 +374,7 @@ char* get_hdr_field(char* buf, char* end, struct hdr_field* hdr) give you the first occurrence of a header you are interested in, look at check_transaction_quadruple */ -int parse_headers(struct sip_msg* msg, hdr_flags_t flags, int next) +int parse_headers_aux(struct sip_msg* msg, hdr_flags_t flags, int next, int sip_well_known_parse) { struct hdr_field *hf; struct hdr_field *itr; @@ -329,7 +411,7 @@ int parse_headers(struct sip_msg* msg, hdr_flags_t flags, int next) } memset(hf,0, sizeof(struct hdr_field)); hf->type=HDR_ERROR_T; - rest=get_hdr_field(tmp, msg->buf+msg->len, hf); + rest=get_hdr_field_aux(tmp, msg->buf+msg->len, hf,sip_well_known_parse); switch (hf->type){ case HDR_ERROR_T: LM_INFO("bad header field\n"); @@ -511,19 +593,21 @@ int parse_headers(struct sip_msg* msg, hdr_flags_t flags, int next) link_sibling_hdr(h_via1,hf); msg->parsed_flag|=HDR_VIA_F; LM_DBG("via found, flags=%llx\n", (unsigned long long)flags); - if (msg->via1==0) { - LM_DBG("this is the first via\n"); - msg->h_via1=hf; - msg->via1=hf->parsed; - if (msg->via1->next){ - msg->via2=msg->via1->next; + if (sip_well_known_parse) { + if (msg->via1==0) { + LM_DBG("this is the first via\n"); + msg->h_via1=hf; + msg->via1=hf->parsed; + if (msg->via1->next){ + msg->via2=msg->via1->next; + msg->parsed_flag|=HDR_VIA2_F; + } + }else if (msg->via2==0){ + msg->h_via2=hf; + msg->via2=hf->parsed; msg->parsed_flag|=HDR_VIA2_F; + LM_DBG("parse_headers: this is the second via\n"); } - }else if (msg->via2==0){ - msg->h_via2=hf; - msg->via2=hf->parsed; - msg->parsed_flag|=HDR_VIA2_F; - LM_DBG("parse_headers: this is the second via\n"); } break; case HDR_FEATURE_CAPS_T: diff --git a/parser/msg_parser.h b/parser/msg_parser.h index a6ab5ed1c32..ac317abed53 100644 --- a/parser/msg_parser.h +++ b/parser/msg_parser.h @@ -355,9 +355,13 @@ extern int via_cnt; int parse_msg(char* buf, unsigned int len, struct sip_msg* msg); -int parse_headers(struct sip_msg* msg, hdr_flags_t flags, int next); +#define parse_headers(msg, flags,next) parse_headers_aux(msg,flags,next, 1) -char* get_hdr_field(char* buf, char* end, struct hdr_field* hdr); +int parse_headers_aux(struct sip_msg* msg, hdr_flags_t flags, int next, int sip_well_known_parse); + +#define get_hdr_field(buf,end,hdr) get_hdr_field_aux(buf,end,hdr,1) + +char* get_hdr_field_aux(char* buf, char* end, struct hdr_field* hdr, int sip_well_known_parse); void free_sip_msg(struct sip_msg* msg);