Skip to content

Commit

Permalink
Support overlapping SIP&HTTP headers in WS HTTP initial requests
Browse files Browse the repository at this point in the history
  • Loading branch information
vladpaiu committed Oct 30, 2023
1 parent c442ae6 commit e30a355
Show file tree
Hide file tree
Showing 3 changed files with 180 additions and 92 deletions.
4 changes: 2 additions & 2 deletions modules/proto_ws/ws_handshake_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}
Expand Down
260 changes: 172 additions & 88 deletions parser/msg_parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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( match<end &&( (*match==' ')||(*match=='\t') ) );
tmp=match;
hdr->body.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( match<end &&( (*match==' ')||(*match=='\t') ) );
tmp=match;
hdr->body.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( match<end &&( (*match==' ')||(*match=='\t') ) );
tmp=match;
hdr->body.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( match<end &&( (*match==' ')||(*match=='\t') ) );
tmp=match;
hdr->body.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:
Expand Down Expand Up @@ -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 */
Expand All @@ -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;
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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:
Expand Down
8 changes: 6 additions & 2 deletions parser/msg_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down

0 comments on commit e30a355

Please sign in to comment.