For (non-heuristic) SIP-over-TCP, dissect stuff that's neither a request

nor a response as continuation data.  For SIP-over-everything-else,
reject it.

Parse the headers regardless of whether we're building a protocol tree
or not; if we're not, we just do it to look for a blank line separating
the headers from the body.  Do that instead of scanning for the message
body separately.

When scanning for a colon, don't scan past the end of the line.

svn path=/trunk/; revision=8549
This commit is contained in:
Guy Harris 2003-09-26 21:32:38 +00:00
parent f3832721d9
commit ae3aa9d05b
1 changed files with 117 additions and 130 deletions

View File

@ -17,7 +17,7 @@
* Copyright 2000, Heikki Vatiainen <hessu@cs.tut.fi>
* Copyright 2001, Jean-Francois Mule <jfm@cablelabs.com>
*
* $Id: packet-sip.c,v 1.43 2003/09/26 20:00:38 guy Exp $
* $Id: packet-sip.c,v 1.44 2003/09/26 21:32:38 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@ -260,57 +260,26 @@ typedef enum {
/* global_sip_raw_text determines whether we are going to display */
/* the raw text of the SIP message, much like the MEGACO dissector does. */
static gboolean global_sip_raw_text = FALSE;
static gboolean dissect_sip_common(tvbuff_t *tvb, packet_info *pinfo,
proto_tree *tree, gboolean is_heur);
static line_type_t sip_parse_line(tvbuff_t *tvb, gint eol, guint *token_1_len);
static line_type_t sip_parse_line(tvbuff_t *tvb, gint linelen,
guint *token_1_len);
static gboolean sip_is_known_request(tvbuff_t *tvb, int meth_offset,
guint meth_len);
static gint sip_get_msg_offset(tvbuff_t *tvb, int offset);
static gint sip_is_known_sip_header(tvbuff_t *tvb, int offset,
guint header_len);
void dfilter_sip_request_line(tvbuff_t *tvb, proto_tree *tree, guint meth_len);
void dfilter_sip_status_line(tvbuff_t *tvb, proto_tree *tree);
static void dfilter_sip_request_line(tvbuff_t *tvb, proto_tree *tree,
guint meth_len);
static void dfilter_sip_status_line(tvbuff_t *tvb, proto_tree *tree);
static void tvb_raw_text_add(tvbuff_t *tvb, proto_tree *tree);
static dissector_handle_t sdp_handle;
static dissector_handle_t data_handle;
static void
tvb_raw_text_add(tvbuff_t *tvb, proto_tree *tree);
#define SIP2_HDR "SIP/2.0"
#define SIP2_HDR_LEN (strlen (SIP2_HDR))
/* Copied from MGCP dissector, prints whole message in raw text */
static void tvb_raw_text_add(tvbuff_t *tvb, proto_tree *tree){
proto_tree *raw_tree;
proto_item *ti;
gint tvb_linebegin,tvb_lineend,tvb_len,linelen;
ti = proto_tree_add_item(tree, proto_raw_sip, tvb, 0, -1, FALSE);
raw_tree = proto_item_add_subtree(ti, ett_raw_text);
tvb_linebegin = 0;
tvb_len = tvb_length(tvb);
do {
tvb_find_line_end(tvb,tvb_linebegin,-1,&tvb_lineend,FALSE);
linelen = tvb_lineend - tvb_linebegin;
proto_tree_add_text(raw_tree, tvb, tvb_linebegin, linelen,
"%s", tvb_format_text(tvb,tvb_linebegin,
linelen));
tvb_linebegin = tvb_lineend;
} while ( tvb_lineend < tvb_len );
}
/* Code to actually dissect the packets */
static int
dissect_sip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
@ -320,23 +289,31 @@ dissect_sip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
return tvb_length(tvb);
}
static void
dissect_sip_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
dissect_sip_common(tvb, pinfo, tree, TRUE);
}
static gboolean
dissect_sip_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
return dissect_sip_common(tvb, pinfo, tree, TRUE);
return dissect_sip_common(tvb, pinfo, tree, FALSE);
}
static gboolean
dissect_sip_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
gboolean is_heur)
gboolean dissect_other_as_continuation)
{
int offset;
gint eol, next_offset, msg_offset;
gint next_offset, linelen;
line_type_t line_type;
tvbuff_t *next_tvb;
gboolean is_known_request;
char *descr;
guint token_1_len;
proto_item *ts = NULL, *ti, *th = NULL;
proto_tree *sip_tree, *reqresp_tree, *hdr_tree = NULL;
/*
* Note that "tvb_find_line_end()" will return a value that
@ -347,28 +324,22 @@ dissect_sip_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
* "sip_parse_line()" won't throw an exception.
*/
offset = 0;
eol = tvb_find_line_end(tvb, 0, -1, &next_offset, FALSE);
line_type = sip_parse_line(tvb, eol, &token_1_len);
linelen = tvb_find_line_end(tvb, 0, -1, &next_offset, FALSE);
line_type = sip_parse_line(tvb, linelen, &token_1_len);
if (line_type == OTHER_LINE) {
/*
* This is neither a SIP request nor response.
*/
if (is_heur) {
if (!dissect_other_as_continuation) {
/*
* This is a heuristic dissector, which means we get
* all the UDP and TCP traffic not sent to a known
* dissector and not claimed by a heuristic dissector
* called before us!
*
* Therefore, we reject this as not being for us.
* We were asked to reject this.
*/
return FALSE;
} else {
/*
* Just dissect it as data.
*/
goto bad;
}
/*
* Just dissect it as a continuation.
*/
}
if (check_col(pinfo->cinfo, COL_PROTOCOL))
@ -382,7 +353,7 @@ dissect_sip_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
if (check_col(pinfo->cinfo, COL_INFO)) {
col_add_fstr(pinfo->cinfo, COL_INFO, "%s: %s",
descr,
tvb_format_text(tvb, 0, eol - SIP2_HDR_LEN - 1));
tvb_format_text(tvb, 0, linelen - SIP2_HDR_LEN - 1));
}
break;
@ -390,7 +361,7 @@ dissect_sip_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
descr = "Status";
if (check_col(pinfo->cinfo, COL_INFO)) {
col_add_fstr(pinfo->cinfo, COL_INFO, "Status: %s",
tvb_format_text(tvb, SIP2_HDR_LEN + 1, eol - SIP2_HDR_LEN - 1));
tvb_format_text(tvb, SIP2_HDR_LEN + 1, linelen - SIP2_HDR_LEN - 1));
}
break;
@ -401,18 +372,14 @@ dissect_sip_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
col_set_str(pinfo->cinfo, COL_INFO, "Continuation");
break;
}
msg_offset = sip_get_msg_offset(tvb, offset);
if (tree) {
proto_item *ti, *th;
proto_tree *sip_tree, *reqresp_tree, *hdr_tree;
ti = proto_tree_add_item(tree, proto_sip, tvb, 0, -1, FALSE);
sip_tree = proto_item_add_subtree(ti, ett_sip);
ts = proto_tree_add_item(tree, proto_sip, tvb, 0, -1, FALSE);
sip_tree = proto_item_add_subtree(ts, ett_sip);
ti = proto_tree_add_text(sip_tree, tvb, 0, next_offset,
"%s line: %s", descr,
tvb_format_text(tvb, 0, eol));
tvb_format_text(tvb, 0, linelen));
reqresp_tree = proto_item_add_subtree(ti, ett_sip_reqresp);
switch (line_type) {
@ -426,28 +393,46 @@ dissect_sip_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
break;
case OTHER_LINE:
break;
proto_tree_add_text(sip_tree, tvb, 0, -1,
"Continuation data");
return TRUE;
}
offset = next_offset;
th = proto_tree_add_item(sip_tree, hf_msg_hdr, tvb, offset, msg_offset - offset, FALSE);
th = proto_tree_add_item(sip_tree, hf_msg_hdr, tvb, offset, -1,
FALSE);
hdr_tree = proto_item_add_subtree(th, ett_sip_hdr);
}
/* - 2 since we have a CRLF separating the message-body */
while (msg_offset - 2 > (int) offset) {
gint line_end_offset;
gint colon_offset;
gint header_len;
gint hf_index;
gint value_offset;
guchar c;
size_t value_len;
char *value;
/*
* Process the headers - if we're not building a protocol tree,
* we just do this to find the blank line separating the
* headers from the message body.
*/
next_offset = offset;
while (tvb_reported_length_remaining(tvb, offset) > 0) {
gint line_end_offset;
gint colon_offset;
gint header_len;
gint hf_index;
gint value_offset;
guchar c;
size_t value_len;
char *value;
eol = tvb_find_line_end(tvb, offset, -1, &next_offset,
FALSE);
line_end_offset = offset + eol;
colon_offset = tvb_find_guint8(tvb, offset, -1, ':');
linelen = tvb_find_line_end(tvb, offset, -1, &next_offset,
FALSE);
if (linelen == 0) {
/*
* This is a blank line separating the
* message header from the message body.
*/
break;
}
if (tree) {
line_end_offset = offset + linelen;
colon_offset = tvb_find_guint8(tvb, offset, linelen,
':');
if (colon_offset == -1) {
/*
* Malformed header - no colon after the
@ -455,7 +440,7 @@ dissect_sip_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
*/
proto_tree_add_text(hdr_tree, tvb, offset,
next_offset - offset, "%s",
tvb_format_text(tvb, offset, eol));
tvb_format_text(tvb, offset, linelen));
} else {
header_len = colon_offset - offset;
hf_index = sip_is_known_sip_header(tvb,
@ -464,7 +449,7 @@ dissect_sip_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
if (hf_index == -1) {
proto_tree_add_text(hdr_tree, tvb,
offset, next_offset - offset, "%s",
tvb_format_text(tvb, offset, eol));
tvb_format_text(tvb, offset, linelen));
} else {
/*
* Skip whitespace after the colon.
@ -490,33 +475,35 @@ dissect_sip_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
hf_header_array[hf_index], tvb,
offset, next_offset - offset,
value, "%s",
tvb_format_text(tvb, offset, eol));
tvb_format_text(tvb, offset, linelen));
g_free(value);
}
}
offset = next_offset;
}
offset += 2; /* Skip the CRLF mentioned above */
offset = next_offset;
}
if (tvb_offset_exists(tvb, msg_offset)) {
next_tvb = tvb_new_subset(tvb, msg_offset, -1, -1);
if (tvb_offset_exists(tvb, next_offset)) {
/*
* There's a message body starting at "next_offset".
* Set the length of the SIP portion and of the
* header item.
*/
proto_item_set_end(ts, tvb, next_offset);
proto_item_set_end(th, tvb, next_offset);
next_tvb = tvb_new_subset(tvb, next_offset, -1, -1);
call_dissector(sdp_handle, next_tvb, pinfo, tree);
}
if(global_sip_raw_text)
tvb_raw_text_add(tvb, tree);
return TRUE;
bad:
next_tvb = tvb_new_subset(tvb, offset, -1, -1);
call_dissector(data_handle,next_tvb, pinfo, tree);
if (global_sip_raw_text)
tvb_raw_text_add(tvb, tree);
return TRUE;
}
/* Display filter for SIP Request-Line */
void dfilter_sip_request_line(tvbuff_t *tvb, proto_tree *tree, guint meth_len)
static void
dfilter_sip_request_line(tvbuff_t *tvb, proto_tree *tree, guint meth_len)
{
char *string;
@ -530,7 +517,8 @@ void dfilter_sip_request_line(tvbuff_t *tvb, proto_tree *tree, guint meth_len)
}
/* Display filter for SIP Status-Line */
void dfilter_sip_status_line(tvbuff_t *tvb, proto_tree *tree)
static void
dfilter_sip_status_line(tvbuff_t *tvb, proto_tree *tree)
{
char string[3+1];
@ -546,32 +534,6 @@ void dfilter_sip_status_line(tvbuff_t *tvb, proto_tree *tree)
3, string);
}
/* Returns the offset to the start of the optional message-body, or
* an offset just past the end of the packet if not found.
*/
static gint sip_get_msg_offset(tvbuff_t *tvb, int offset)
{
gint linelen, next_offset;
while (tvb_offset_exists(tvb, offset)) {
linelen = tvb_find_line_end(tvb, offset, -1, &next_offset,
FALSE);
/*
* If the line length is 0, this is a blank line;
* we're done.
*/
if (linelen == 0)
break;
offset = next_offset;
}
/*
* Return the offset just past the line we just processed (or
* past the end of the buffer if we didn't find a blank line).
*/
return next_offset;
}
/* From section 4.1 of RFC 2543:
*
* Request-Line = Method SP Request-URI SP SIP-Version CRLF
@ -581,7 +543,7 @@ static gint sip_get_msg_offset(tvbuff_t *tvb, int offset)
* Status-Line = SIP-version SP Status-Code SP Reason-Phrase CRLF
*/
static line_type_t
sip_parse_line(tvbuff_t *tvb, gint eol, guint *token_1_lenp)
sip_parse_line(tvbuff_t *tvb, gint linelen, guint *token_1_lenp)
{
gint space_offset;
guint token_1_len;
@ -616,7 +578,7 @@ sip_parse_line(tvbuff_t *tvb, gint eol, guint *token_1_lenp)
}
token_2_len = space_offset - token_2_start;
token_3_start = space_offset + 1;
token_3_len = eol - token_3_start;
token_3_len = linelen - token_3_start;
*token_1_lenp = token_1_len;
@ -714,6 +676,30 @@ static gint sip_is_known_sip_header(tvbuff_t *tvb, int offset, guint header_len)
return -1;
}
/*
* Display the entire message as raw text.
*/
static void
tvb_raw_text_add(tvbuff_t *tvb, proto_tree *tree)
{
proto_tree *raw_tree;
proto_item *ti;
int offset, next_offset, linelen;
ti = proto_tree_add_item(tree, proto_raw_sip, tvb, 0, -1, FALSE);
raw_tree = proto_item_add_subtree(ti, ett_raw_text);
offset = 0;
while (tvb_offset_exists(tvb, offset)) {
tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE);
linelen = next_offset - offset;
proto_tree_add_text(raw_tree, tvb, offset, linelen,
"%s", tvb_format_text(tvb, offset, linelen));
offset = next_offset;
}
}
/* Register the protocol with Ethereal */
void proto_register_sip(void)
{
@ -1021,19 +1007,20 @@ void proto_register_sip(void)
void
proto_reg_handoff_sip(void)
{
dissector_handle_t sip_handle;
dissector_handle_t sip_handle, sip_tcp_handle;
sip_handle = new_create_dissector_handle(dissect_sip, proto_sip);
dissector_add("tcp.port", TCP_PORT_SIP, sip_handle);
dissector_add("udp.port", UDP_PORT_SIP, sip_handle);
heur_dissector_add( "udp", dissect_sip_heur, proto_sip );
heur_dissector_add( "tcp", dissect_sip_heur, proto_sip );
heur_dissector_add( "sctp", dissect_sip_heur, proto_sip );
sip_tcp_handle = create_dissector_handle(dissect_sip_tcp, proto_sip);
dissector_add("tcp.port", TCP_PORT_SIP, sip_tcp_handle);
heur_dissector_add("udp", dissect_sip_heur, proto_sip);
heur_dissector_add("tcp", dissect_sip_heur, proto_sip);
heur_dissector_add("sctp", dissect_sip_heur, proto_sip);
/*
* Get a handle for the SDP dissector.
*/
sdp_handle = find_dissector("sdp");
data_handle = find_dissector("data");
}