From Anders Broman: make it possible to filter on only address or tag in
[obnox/wireshark/wip.git] / packet-sip.c
1 /* packet-sip.c
2  * Routines for the Session Initiation Protocol (SIP) dissection.
3  * RFCs 3261-3264
4  *
5  * TODO: Pay attention to Content-Type: It might not always be SDP.
6  *       hf_ display filters for headers of SIP extension RFCs: 
7  *              Done for RFC 3265, RFC 3262
8  *              Use hash table for list of headers
9  *       Add sip msg body dissection based on Content-Type for:
10  *                SDP, MIME, and other types
11  *       Align SIP methods with recent Internet Drafts or RFC
12  *               (SIP INFO, rfc2976 - done)
13  *               (SIP SUBSCRIBE-NOTIFY - done)
14  *               (SIP REFER - done)
15  *               check for other
16  *
17  * Copyright 2000, Heikki Vatiainen <hessu@cs.tut.fi>
18  * Copyright 2001, Jean-Francois Mule <jfm@cablelabs.com>
19  *
20  * $Id: packet-sip.c,v 1.46 2003/10/24 00:50:39 guy Exp $
21  *
22  * Ethereal - Network traffic analyzer
23  * By Gerald Combs <gerald@ethereal.com>
24  * Copyright 1998 Gerald Combs
25  *
26  * Copied from packet-cops.c
27  *
28  * This program is free software; you can redistribute it and/or
29  * modify it under the terms of the GNU General Public License
30  * as published by the Free Software Foundation; either version 2
31  * of the License, or (at your option) any later version.
32  *
33  * This program is distributed in the hope that it will be useful,
34  * but WITHOUT ANY WARRANTY; without even the implied warranty of
35  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
36  * GNU General Public License for more details.
37  *
38  * You should have received a copy of the GNU General Public License
39  * along with this program; if not, write to the Free Software
40  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
41  */
42
43 #ifdef HAVE_CONFIG_H
44 # include "config.h"
45 #endif
46
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <ctype.h>
51
52 #include "prefs.h"
53
54 #include <glib.h>
55 #include <epan/packet.h>
56
57 #define TCP_PORT_SIP 5060
58 #define UDP_PORT_SIP 5060
59
60 /* Initialize the protocol and registered fields */
61 static gint proto_sip = -1;
62 static gint proto_raw_sip = -1;
63 static gint hf_msg_hdr = -1;
64 static gint hf_Method = -1;
65 static gint hf_Status_Code = -1;
66 static gint hf_sip_to_addr = -1;
67 static gint hf_sip_from_addr = -1;
68 static gint hf_sip_tag = -1;
69
70 /* Initialize the subtree pointers */
71 static gint ett_sip = -1;
72 static gint ett_sip_reqresp = -1;
73 static gint ett_sip_hdr = -1;
74 static gint ett_raw_text = -1;
75 static gint ett_sip_element = -1;
76
77 static const char *sip_methods[] = {
78         "<Invalid method>",      /* Pad so that the real methods start at index 1 */
79         "ACK",
80         "BYE",
81         "CANCEL",
82         "DO",
83         "INFO",
84         "INVITE",
85         "MESSAGE",
86         "NOTIFY",
87         "OPTIONS",
88         "PRACK",
89         "QAUTH",
90         "REFER",
91         "REGISTER",
92         "SPRACK",
93         "SUBSCRIBE",
94         "UPDATE"
95 };
96
97 /* from RFC 3261 */
98 static const char *sip_headers[] = {
99                 "Unknown-header", /* Pad so that the real headers start at index 1 */
100                 "Accept",
101                 "Accept-Encoding",
102                 "Accept-Language",
103                 "Alert-Info",
104                 "Allow",
105                 "Allow-Events",
106                 "Authentication-Info",
107                 "Authorization",
108                 "Call-ID",
109                 "Call-Info",
110                 "Contact",
111                 "Content-Disposition",
112                 "Content-Encoding",
113                 "Content-Language",
114                 "Content-Length",
115                 "Content-Type",
116                 "CSeq",
117                 "Date",
118                 "Error-Info",
119                 "Event",
120                 "Expires",
121                 "From",
122                 "In-Reply-To",
123                 "Max-Forwards",
124                 "MIME-Version",
125                 "Min-Expires",
126                 "Organization",
127                 "Priority",
128                 "Proxy-Authenticate",
129                 "Proxy-Authorization",
130                 "Proxy-Require",
131                 "RAck",
132                 "RSeq",
133                 "Record-Route",
134                 "Reply-To",
135                 "Require",
136                 "Retry-After",
137                 "Route",
138                 "Server",
139                 "Subject",
140                 "Subscription-State",
141                 "Supported",
142                 "Timestamp",
143                 "To",
144                 "Unsupported",
145                 "User-Agent",
146                 "Via",
147                 "Warning",
148                 "WWW-Authenticate"
149 };
150
151
152 #define POS_ACCEPT              1
153 #define POS_ACCEPT_ENCODING     2
154 #define POS_ACCEPT_LANGUAGE     3
155 #define POS_ALERT_INFO          4
156 #define POS_ALLOW               5
157 #define POS_ALLOW_EVENTS        6
158 #define POS_AUTHENTICATION_INFO 7
159 #define POS_AUTHORIZATION       8
160 #define POS_CALL_ID             9
161 #define POS_CALL_INFO           10
162 #define POS_CONTACT             11
163 #define POS_CONTENT_DISPOSITION 12
164 #define POS_CONTENT_ENCODING    13
165 #define POS_CONTENT_LANGUAGE    14
166 #define POS_CONTENT_LENGTH      15
167 #define POS_CONTENT_TYPE        16
168 #define POS_CSEQ                17
169 #define POS_DATE                18
170 #define POS_ERROR_INFO          19
171 #define POS_EVENT               20
172 #define POS_EXPIRES             21
173 #define POS_FROM                22
174 #define POS_IN_REPLY_TO         23
175 #define POS_MAX_FORWARDS        24
176 #define POS_MIME_VERSION        25
177 #define POS_MIN_EXPIRES         26
178 #define POS_ORGANIZATION        27
179 #define POS_PRIORITY            28
180 #define POS_PROXY_AUTHENTICATE  29
181 #define POS_PROXY_AUTHORIZATION 30
182 #define POS_PROXY_REQUIRE       31
183 #define POS_RACK                32
184 #define POS_RSEQ                33
185 #define POS_RECORD_ROUTE        34
186 #define POS_REPLY_TO            35
187 #define POS_REQUIRE             36
188 #define POS_RETRY_AFTER         37
189 #define POS_ROUTE               38
190 #define POS_SERVER              39
191 #define POS_SUBJECT             40
192 #define POS_SUBSCRIPTION_STATE  41
193 #define POS_SUPPORTED           42
194 #define POS_TIMESTAMP           43
195 #define POS_TO                  44
196 #define POS_UNSUPPORTED         45
197 #define POS_USER_AGENT          46
198 #define POS_VIA                 47
199 #define POS_WARNING             48
200 #define POS_WWW_AUTHENTICATE    49
201
202 static gint hf_header_array[] = {
203                 -1, /* "Unknown-header" - Pad so that the real headers start at index 1 */
204                 -1, /* "Accept" */
205                 -1, /* "Accept-Encoding" */
206                 -1, /* "Accept-Language" */
207                 -1, /* "Alert-Info" */
208                 -1, /* "Allow" */
209                 -1, /* "Allow-Events" - RFC 3265 */
210                 -1, /* "Authentication-Info" */
211                 -1, /* "Authorization" */
212                 -1, /* "Call-ID" */
213                 -1, /* "Call-Info" */
214                 -1, /* "Contact" */
215                 -1, /* "Content-Disposition" */
216                 -1, /* "Content-Encoding" */
217                 -1, /* "Content-Language" */
218                 -1, /* "Content-Length" */
219                 -1, /* "Content-Type" */
220                 -1, /* "CSeq" */
221                 -1, /* "Date" */
222                 -1, /* "Error-Info" */
223                 -1, /* "Expires" */
224                 -1, /* "Event" - RFC 3265 */
225                 -1, /* "From" */
226                 -1, /* "In-Reply-To" */
227                 -1, /* "Max-Forwards" */
228                 -1, /* "MIME-Version" */
229                 -1, /* "Min-Expires" */
230                 -1, /* "Organization" */
231                 -1, /* "Priority" */
232                 -1, /* "Proxy-Authenticate" */
233                 -1, /* "Proxy-Authorization" */
234                 -1, /* "Proxy-Require" */
235                 -1, /* "RAck" - RFC 3262 */
236                 -1, /* "RSeq" - RFC 3261 */
237                 -1, /* "Record-Route" */
238                 -1, /* "Reply-To" */
239                 -1, /* "Require" */
240                 -1, /* "Retry-After" */
241                 -1, /* "Route" */
242                 -1, /* "Server" */
243                 -1, /* "Subject" */
244                 -1, /* "Subscription-State" - RFC 3265 */
245                 -1, /* "Supported" */
246                 -1, /* "Timestamp" */
247                 -1, /* "To" */
248                 -1, /* "Unsupported" */
249                 -1, /* "User-Agent" */
250                 -1, /* "Via" */
251                 -1, /* "Warning" */
252                 -1  /* "WWW-Authenticate" */
253 };
254
255 /*
256  * Type of line.  It's either a SIP Request-Line, a SIP Status-Line, or
257  * another type of line.
258  */
259 typedef enum {
260         REQUEST_LINE,
261         STATUS_LINE,
262         OTHER_LINE
263 } line_type_t;
264
265 /* global_sip_raw_text determines whether we are going to display               */
266 /* the raw text of the SIP message, much like the MEGACO dissector does.        */
267 static gboolean global_sip_raw_text = FALSE;
268
269 static gboolean dissect_sip_common(tvbuff_t *tvb, packet_info *pinfo,
270     proto_tree *tree, gboolean is_heur);
271 static line_type_t sip_parse_line(tvbuff_t *tvb, gint linelen,
272     guint *token_1_len);
273 static gboolean sip_is_known_request(tvbuff_t *tvb, int meth_offset,
274     guint meth_len);
275 static gint sip_is_known_sip_header(tvbuff_t *tvb, int offset,
276     guint header_len);
277 static void dfilter_sip_request_line(tvbuff_t *tvb, proto_tree *tree,
278     guint meth_len);
279 static void dfilter_sip_status_line(tvbuff_t *tvb, proto_tree *tree);
280 static void tvb_raw_text_add(tvbuff_t *tvb, proto_tree *tree);
281
282 static dissector_handle_t sdp_handle;
283
284 #define SIP2_HDR "SIP/2.0"
285 #define SIP2_HDR_LEN (strlen (SIP2_HDR))
286
287 /* Code to actually dissect the packets */
288 static int
289 dissect_sip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
290 {
291         if (!dissect_sip_common(tvb, pinfo, tree, FALSE))
292                 return 0;
293         return tvb_length(tvb);
294 }
295
296 static void
297 dissect_sip_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
298 {
299         dissect_sip_common(tvb, pinfo, tree, TRUE);
300 }
301
302 static gboolean
303 dissect_sip_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
304 {
305         return dissect_sip_common(tvb, pinfo, tree, FALSE);
306 }
307
308 static gboolean
309 dissect_sip_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
310     gboolean dissect_other_as_continuation)
311 {
312         int offset;
313         gint next_offset, linelen;
314         line_type_t line_type;
315         tvbuff_t *next_tvb;
316         gboolean is_known_request;
317         char *descr;
318         guint token_1_len;
319         proto_item *ts = NULL, *ti, *th = NULL, *sip_element_item;
320         proto_tree *sip_tree, *reqresp_tree, *hdr_tree = NULL, *sip_element_tree;
321
322         /*
323          * Note that "tvb_find_line_end()" will return a value that
324          * is not longer than what's in the buffer, so the
325          * "tvb_get_ptr()" calls below won't throw exceptions.
326          *
327          * Note that "tvb_strneql()" doesn't throw exceptions, so
328          * "sip_parse_line()" won't throw an exception.
329          */
330         offset = 0;
331         linelen = tvb_find_line_end(tvb, 0, -1, &next_offset, FALSE);
332         line_type = sip_parse_line(tvb, linelen, &token_1_len);
333         if (line_type == OTHER_LINE) {
334                 /*
335                  * This is neither a SIP request nor response.
336                  */
337                 if (!dissect_other_as_continuation) {
338                         /*
339                          * We were asked to reject this.
340                          */
341                         return FALSE;
342                 }
343
344                 /*
345                  * Just dissect it as a continuation.
346                  */
347         }
348
349         if (check_col(pinfo->cinfo, COL_PROTOCOL))
350                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "SIP");
351
352         switch (line_type) {
353
354         case REQUEST_LINE:
355                 is_known_request = sip_is_known_request(tvb, 0, token_1_len);
356                 descr = is_known_request ? "Request" : "Unknown request";
357                 if (check_col(pinfo->cinfo, COL_INFO)) {
358                         col_add_fstr(pinfo->cinfo, COL_INFO, "%s: %s",
359                              descr,
360                              tvb_format_text(tvb, 0, linelen - SIP2_HDR_LEN - 1));
361                 }
362                 break;
363
364         case STATUS_LINE:
365                 descr = "Status";
366                 if (check_col(pinfo->cinfo, COL_INFO)) {
367                         col_add_fstr(pinfo->cinfo, COL_INFO, "Status: %s",
368                              tvb_format_text(tvb, SIP2_HDR_LEN + 1, linelen - SIP2_HDR_LEN - 1));
369                 }
370                 break;
371
372         case OTHER_LINE:
373         default: /* Squelch compiler complaints */
374                 descr = "Continuation";
375                 if (check_col(pinfo->cinfo, COL_INFO))
376                         col_set_str(pinfo->cinfo, COL_INFO, "Continuation");
377                 break;
378         }
379
380         if (tree) {
381                 ts = proto_tree_add_item(tree, proto_sip, tvb, 0, -1, FALSE);
382                 sip_tree = proto_item_add_subtree(ts, ett_sip);
383
384                 ti = proto_tree_add_text(sip_tree, tvb, 0, next_offset,
385                                          "%s line: %s", descr,
386                                          tvb_format_text(tvb, 0, linelen));
387                 reqresp_tree = proto_item_add_subtree(ti, ett_sip_reqresp);
388
389                 switch (line_type) {
390
391                 case REQUEST_LINE:
392                         dfilter_sip_request_line(tvb, reqresp_tree, token_1_len);
393                         break;
394
395                 case STATUS_LINE:
396                         dfilter_sip_status_line(tvb, reqresp_tree);
397                         break;
398
399                 case OTHER_LINE:
400                         proto_tree_add_text(sip_tree, tvb, 0, -1,
401                             "Continuation data");
402                         return TRUE;
403                 }
404
405                 offset = next_offset;
406                 th = proto_tree_add_item(sip_tree, hf_msg_hdr, tvb, offset, -1,
407                     FALSE);
408                 hdr_tree = proto_item_add_subtree(th, ett_sip_hdr);
409         }
410
411         /*
412          * Process the headers - if we're not building a protocol tree,
413          * we just do this to find the blank line separating the
414          * headers from the message body.
415          */
416         next_offset = offset;
417         while (tvb_reported_length_remaining(tvb, offset) > 0) {
418                 gint line_end_offset;
419                 gint colon_offset;
420                 gint header_len;
421                 gint hf_index;
422                 gint value_offset,tag_offset;
423                 guchar c;
424                 size_t value_len;
425                 char *value;
426
427                 linelen = tvb_find_line_end(tvb, offset, -1, &next_offset,
428                     FALSE);
429                 if (linelen == 0) {
430                         /*
431                          * This is a blank line separating the
432                          * message header from the message body.
433                          */
434                         break;
435                 }
436                 if (tree) {
437                         line_end_offset = offset + linelen;
438                         colon_offset = tvb_find_guint8(tvb, offset, linelen,
439                             ':');
440                         if (colon_offset == -1) {
441                                 /*
442                                  * Malformed header - no colon after the
443                                  * name.
444                                  */
445                                 proto_tree_add_text(hdr_tree, tvb, offset,
446                                     next_offset - offset, "%s",
447                                     tvb_format_text(tvb, offset, linelen));
448                         } else {
449                                 header_len = colon_offset - offset;
450                                 hf_index = sip_is_known_sip_header(tvb,
451                                     offset, header_len);
452                         
453                                 if (hf_index == -1) {
454                                         proto_tree_add_text(hdr_tree, tvb,
455                                             offset, next_offset - offset, "%s",
456                                             tvb_format_text(tvb, offset, linelen));
457                                 } else {
458                                         /*
459                                          * Skip whitespace after the colon.
460                                          */
461                                         value_offset = colon_offset + 1;
462                                         while (value_offset < line_end_offset
463                                             && ((c = tvb_get_guint8(tvb,
464                                                     value_offset)) == ' '
465                                               || c == '\t'))
466                                                 value_offset++;
467                                         /*
468                                          * Fetch the value.
469                                          */
470                                         value_len = line_end_offset - value_offset;
471                                         value = tvb_get_string(tvb, value_offset,
472                                             value_len);
473
474                                         /*
475                                          * Add it to the protocol tree,
476                                          * but display the line as is.
477                                          */
478
479                                         switch ( hf_index ) {
480                                         case POS_TO :
481                                                 sip_element_item = proto_tree_add_string_format(hdr_tree,
482                                                     hf_header_array[hf_index], tvb,
483                                                 offset, next_offset - offset,
484                                                 value, "%s",
485                                                 tvb_format_text(tvb, offset, linelen));
486                                                 sip_element_tree = proto_item_add_subtree( sip_element_item, ett_sip_element);
487                                                 tag_offset = tvb_find_guint8(tvb, offset,linelen, ';');
488                                                 if ( tag_offset != -1){
489                                                         tag_offset = tag_offset + 1;
490                                                         c = tvb_get_guint8(tvb,tag_offset);
491                                                         if ( c == 't' ){/* tag found */
492                                                                 proto_tree_add_string(sip_element_tree,
493                                                                     hf_sip_to_addr, tvb,
494                                                                         value_offset, (tag_offset - value_offset - 1),
495                                                                 tvb_format_text(tvb, value_offset, ( tag_offset - value_offset - 1)));
496                                                                 tag_offset = tvb_find_guint8(tvb, tag_offset,linelen, '=') + 1;
497                                                                 proto_tree_add_string(sip_element_tree,
498                                                                     hf_sip_tag, tvb,
499                                                                         tag_offset, (line_end_offset - tag_offset),
500                                                                 tvb_format_text(tvb, tag_offset, (line_end_offset - tag_offset)));
501                                                         
502                                                         }
503                                                         else {
504                                                                 proto_tree_add_string_format(sip_element_tree,
505                                                                     hf_sip_to_addr, tvb,
506                                                                 offset, line_end_offset - offset,
507                                                                 value, "%s",
508                                                                 tvb_format_text(tvb, offset, linelen));
509                                                         }/* if c= t */
510                                                 } /* if tag offset */
511                                         break;  
512                                         case POS_FROM :
513                                                 sip_element_item = proto_tree_add_string_format(hdr_tree,
514                                                     hf_header_array[hf_index], tvb,
515                                                 offset, next_offset - offset,
516                                                 value, "%s",
517                                                 tvb_format_text(tvb, offset, linelen));
518                                                 sip_element_tree = proto_item_add_subtree( sip_element_item, ett_sip_element);
519                                                 tag_offset = tvb_find_guint8(tvb, offset,linelen, ';');
520                                                 if ( tag_offset != -1){
521                                                         tag_offset = tag_offset + 1;
522                                                         c = tvb_get_guint8(tvb,tag_offset);
523                                                         if ( c == 't' ){/* tag found */
524                                                                 proto_tree_add_string(sip_element_tree,
525                                                                     hf_sip_from_addr, tvb,
526                                                                         value_offset, (tag_offset - value_offset - 1),
527                                                                 tvb_format_text(tvb, value_offset, ( tag_offset - value_offset - 1)));
528                                                                 tag_offset = tvb_find_guint8(tvb, offset,linelen, '=') + 1;
529                                                                 proto_tree_add_string(sip_element_tree,
530                                                                     hf_sip_tag, tvb,
531                                                                         tag_offset, (line_end_offset - tag_offset),
532                                                                 tvb_format_text(tvb, tag_offset, (line_end_offset - tag_offset)));
533                                                         
534                                                         }
535                                                         else {
536                                                                 tag_offset = tvb_find_guint8(tvb, tag_offset,linelen, ';');
537                                                                 if ( tag_offset != -1){
538                                                                         tag_offset = tag_offset + 1;
539                                                                         c = tvb_get_guint8(tvb,tag_offset);
540                                                                         if ( c == 't' ){/* tag found */
541                                                                                 proto_tree_add_string(sip_element_tree,
542                                                                                    hf_sip_from_addr, tvb,
543                                                                                    value_offset, (tag_offset - value_offset - 1),
544                                                                                    tvb_format_text(tvb, value_offset, ( tag_offset - value_offset - 1)));
545                                                                                 tag_offset = tvb_find_guint8(tvb, tag_offset,linelen, '=') + 1;
546                                                                                 proto_tree_add_string(sip_element_tree,
547                                                                                   hf_sip_tag, tvb,
548                                                                                   tag_offset, (line_end_offset - tag_offset),
549                                                                                   tvb_format_text(tvb, tag_offset, (line_end_offset - tag_offset)));
550                                                                         }
551                                                                 }
552                                                         }/* if c= t */
553                                                 } /* if tag offset */
554
555                                         break;
556                                         default :       
557                                                 proto_tree_add_string_format(hdr_tree,
558                                                     hf_header_array[hf_index], tvb,
559                                                 offset, next_offset - offset,
560                                                 value, "%s",
561                                                 tvb_format_text(tvb, offset, linelen));
562                                         break;
563                                         }/* end switch */
564                                         g_free(value);
565                                 }/*if HF_index */
566                         }/* if colon_offset */ 
567                 }/* if tree */
568                 offset = next_offset;
569         }/* End while */
570
571         if (tvb_offset_exists(tvb, next_offset)) {
572                 /*
573                  * There's a message body starting at "next_offset".
574                  * Set the length of the SIP portion and of the
575                  * header item.
576                  */
577                 proto_item_set_end(ts, tvb, next_offset);
578                 proto_item_set_end(th, tvb, next_offset);
579                 next_tvb = tvb_new_subset(tvb, next_offset, -1, -1);
580                 call_dissector(sdp_handle, next_tvb, pinfo, tree);
581         }
582
583         if (global_sip_raw_text)
584                 tvb_raw_text_add(tvb, tree);
585
586         return TRUE;
587 }
588
589 /* Display filter for SIP Request-Line */
590 static void
591 dfilter_sip_request_line(tvbuff_t *tvb, proto_tree *tree, guint meth_len)
592 {
593         char    *string;
594
595         /*
596          * We know we have the entire method; otherwise, "sip_parse_line()"
597          * would have returned OTHER_LINE.
598          */
599         string = tvb_get_string(tvb, 0, meth_len);
600         proto_tree_add_string(tree, hf_Method, tvb, 0, meth_len, string);
601         g_free(string);
602 }
603
604 /* Display filter for SIP Status-Line */
605 static void
606 dfilter_sip_status_line(tvbuff_t *tvb, proto_tree *tree)
607 {
608         char string[3+1];
609
610         /*
611          * We know we have the entire status code; otherwise,
612          * "sip_parse_line()" would have returned OTHER_LINE.
613          * We also know that we have a version string followed by a
614          * space at the beginning of the line, for the same reason.
615          */
616         tvb_memcpy(tvb, (guint8 *)string, SIP2_HDR_LEN + 1, 3);
617         string[3] = '\0';
618         proto_tree_add_string(tree, hf_Status_Code, tvb, SIP2_HDR_LEN + 1,
619             3, string);
620 }
621
622 /* From section 4.1 of RFC 2543:
623  *
624  * Request-Line  =  Method SP Request-URI SP SIP-Version CRLF
625  *
626  * From section 5.1 of RFC 2543:
627  *
628  * Status-Line  =  SIP-version SP Status-Code SP Reason-Phrase CRLF
629  */
630 static line_type_t
631 sip_parse_line(tvbuff_t *tvb, gint linelen, guint *token_1_lenp)
632 {
633         gint space_offset;
634         guint token_1_len;
635         gint token_2_start;
636         guint token_2_len;
637         gint token_3_start;
638         guint token_3_len;
639         gint colon_pos;
640
641         space_offset = tvb_find_guint8(tvb, 0, -1, ' ');
642         if (space_offset <= 0) {
643                 /*
644                  * Either there's no space in the line (which means
645                  * the line is empty or doesn't have a token followed
646                  * by a space; neither is valid for a request or status), or
647                  * the first character in the line is a space (meaning
648                  * the method is empty, which isn't valid for a request,
649                  * or the SIP version is empty, which isn't valid for a
650                  * status).
651                  */
652                 return OTHER_LINE;
653         }
654         token_1_len = space_offset;
655         token_2_start = space_offset + 1;
656         space_offset = tvb_find_guint8(tvb, token_2_start, -1, ' ');
657         if (space_offset == -1) {
658                 /*
659                  * There's no space after the second token, so we don't
660                  * have a third token.
661                  */
662                 return OTHER_LINE;
663         }
664         token_2_len = space_offset - token_2_start;
665         token_3_start = space_offset + 1;
666         token_3_len = linelen - token_3_start;
667         
668         *token_1_lenp = token_1_len;
669
670         /*
671          * Is the first token a version string?
672          */
673         if (token_1_len == SIP2_HDR_LEN &&
674             tvb_strneql(tvb, 0, SIP2_HDR, SIP2_HDR_LEN) == 0) {
675                 /*
676                  * Yes, so this is either a Status-Line or something
677                  * else other than a Request-Line.  To be a Status-Line,
678                  * the second token must be a 3-digit number.
679                  */
680                 if (token_2_len != 3) {
681                         /*
682                          * We don't have 3-character status code.
683                          */
684                         return OTHER_LINE;
685                 }
686                 if (!isdigit(tvb_get_guint8(tvb, token_2_start)) ||
687                     !isdigit(tvb_get_guint8(tvb, token_2_start + 1)) ||
688                     !isdigit(tvb_get_guint8(tvb, token_2_start + 2))) {
689                         /*
690                          * 3 characters yes, 3 digits no.
691                          */
692                         return OTHER_LINE;
693                 }
694                 return STATUS_LINE;
695         } else {
696                 /*
697                  * No, so this is either a Request-Line or something
698                  * other than a Status-Line.  To be a Request-Line, the
699                  * second token must be a URI and the third token must
700                  * be a version string.
701                  */
702                 if (token_2_len < 3) {
703                         /*
704                          * We don't have a URI consisting of at least 3
705                          * characters.
706                          */
707                         return OTHER_LINE;
708                 }
709                 colon_pos = tvb_find_guint8(tvb, token_2_start + 1, -1, ':');
710                 if (colon_pos == -1) {
711                         /*
712                          * There is no colon after the method, so the URI
713                          * doesn't have a colon in it, so it's not valid.
714                          */
715                         return OTHER_LINE;
716                 }
717                 if (colon_pos >= token_3_start) {
718                         /*
719                          * The colon is in the version string, not the URI.
720                          */
721                         return OTHER_LINE;
722                 }
723                 /* XXX - Check for a proper URI prefix? */
724                 if (token_3_len != SIP2_HDR_LEN ||
725                     tvb_strneql(tvb, token_3_start, SIP2_HDR, SIP2_HDR_LEN) == -1) {
726                         /*
727                          * The version string isn't an SIP version 2.0 version
728                          * string.
729                          */
730                         return OTHER_LINE;
731                 }
732                 return REQUEST_LINE;
733         }
734 }
735
736 static gboolean sip_is_known_request(tvbuff_t *tvb, int meth_offset,
737     guint meth_len)
738 {
739         guint i;
740
741         for (i = 1; i < array_length(sip_methods); i++) {
742                 if (meth_len == strlen(sip_methods[i]) &&
743                     tvb_strneql(tvb, meth_offset, sip_methods[i], meth_len) == 0)
744                         return TRUE;
745         }
746
747         return FALSE;
748 }
749
750 /* Returns index of method in sip_headers */
751 static gint sip_is_known_sip_header(tvbuff_t *tvb, int offset, guint header_len)
752 {
753         guint i;
754
755         for (i = 1; i < array_length(sip_headers); i++) {
756                 if (header_len == strlen(sip_headers[i]) &&
757                     tvb_strncaseeql(tvb, offset, sip_headers[i], header_len) == 0)
758                         return i;
759         }
760
761         return -1;
762 }
763
764 /*
765  * Display the entire message as raw text.
766  */
767 static void
768 tvb_raw_text_add(tvbuff_t *tvb, proto_tree *tree)
769 {
770         proto_tree *raw_tree;
771         proto_item *ti;
772         int offset, next_offset, linelen;
773
774         ti = proto_tree_add_item(tree, proto_raw_sip, tvb, 0, -1, FALSE);
775         raw_tree = proto_item_add_subtree(ti, ett_raw_text);
776
777         offset = 0;
778
779         while (tvb_offset_exists(tvb, offset)) {
780                 tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE);
781                 linelen = next_offset - offset;
782                 proto_tree_add_text(raw_tree, tvb, offset, linelen,
783                     "%s", tvb_format_text(tvb, offset, linelen));
784                 offset = next_offset;
785         }
786 }
787
788 /* Register the protocol with Ethereal */
789 void proto_register_sip(void)
790 {
791
792         /* Setup list of header fields */
793         static hf_register_info hf[] = {
794
795                 { &hf_msg_hdr,
796                         { "Message Header",           "sip.msg_hdr",
797                         FT_NONE, 0, NULL, 0,
798                         "Message Header in SIP message", HFILL }
799                 },
800                 { &hf_Method,
801                        { "Method",              "sip.Method", 
802                        FT_STRING, BASE_NONE,NULL,0x0,
803                         "SIP Method", HFILL }
804                 },
805                 { &hf_Status_Code,
806                        { "Status-Code",                 "sip.Status-Code", 
807                        FT_STRING, BASE_NONE,NULL,0x0,
808                         "SIP Status Code", HFILL }
809                 },
810                 { &hf_sip_to_addr,
811                        { "SIP to address",              "sip.from_addr", 
812                        FT_STRING, BASE_NONE,NULL,0x0,
813                         "RFC 3261: from addr", HFILL }
814                 },
815                 { &hf_sip_from_addr,
816                        { "SIP from address",            "sip.to_addr", 
817                        FT_STRING, BASE_NONE,NULL,0x0,
818                         "RFC 3261: to addr", HFILL }
819                 },
820                 { &hf_sip_tag,
821                        { "SIP tag",             "sip.tag", 
822                        FT_STRING, BASE_NONE,NULL,0x0,
823                         "RFC 3261: tag", HFILL }
824                 },
825                 { &hf_header_array[POS_ACCEPT],
826                        { "Accept",              "sip.Accept", 
827                        FT_STRING, BASE_NONE,NULL,0x0,
828                         "RFC 3261: Accept Header", HFILL }
829                 },
830                 { &hf_header_array[POS_ACCEPT_ENCODING],
831                        { "Accept-Encoding",             "sip.Accept-Encoding", 
832                        FT_STRING, BASE_NONE,NULL,0x0,
833                         "RFC 3261: Accept-Encoding Header", HFILL }
834                 },
835                 { &hf_header_array[POS_ACCEPT_LANGUAGE],
836                        { "Accept-Language",             "sip.Accept-Language", 
837                        FT_STRING, BASE_NONE,NULL,0x0,
838                         "RFC 3261: Accept-Language Header", HFILL }
839                 },
840                 { &hf_header_array[POS_ALERT_INFO],
841                        { "Alert-Info",          "sip.Alert-Info", 
842                        FT_STRING, BASE_NONE,NULL,0x0,
843                         "RFC 3261: Alert-Info Header", HFILL }
844                 },
845                 { &hf_header_array[POS_ALLOW],
846                        { "Allow",               "sip.Allow", 
847                        FT_STRING, BASE_NONE,NULL,0x0,
848                         "RFC 3261: Allow Header", HFILL }
849                 },
850                 { &hf_header_array[POS_ALLOW_EVENTS],
851                        { "Allow-Events",                "sip.Allow-Events", 
852                        FT_STRING, BASE_NONE,NULL,0x0,
853                         "RFC 3265: Allow-Events Header", HFILL }
854                 },
855                 { &hf_header_array[POS_AUTHENTICATION_INFO],
856                        { "Authentication-Info",                 "sip.Authentication-Info", 
857                        FT_STRING, BASE_NONE,NULL,0x0,
858                         "RFC 3261: Authentication-Info Header", HFILL }
859                 },
860                 { &hf_header_array[POS_AUTHORIZATION],
861                        { "Authorization",               "sip.Authorization", 
862                        FT_STRING, BASE_NONE,NULL,0x0,
863                         "RFC 3261: Authorization Header", HFILL }
864                 },
865                 { &hf_header_array[POS_CALL_ID],
866                        { "Call-ID",             "sip.Call-ID", 
867                        FT_STRING, BASE_NONE,NULL,0x0,
868                         "RFC 3261: Call-ID Header", HFILL }
869                 },
870                 { &hf_header_array[POS_CALL_INFO],
871                        { "Call-Info",           "sip.Call-Info", 
872                        FT_STRING, BASE_NONE,NULL,0x0,
873                         "RFC 3261: Call-Info Header", HFILL }
874                 },
875                 { &hf_header_array[POS_CONTACT],
876                        { "Contact",             "sip.Contact", 
877                        FT_STRING, BASE_NONE,NULL,0x0,
878                         "RFC 3261: Contact Header", HFILL }
879                 },
880                 { &hf_header_array[POS_CONTENT_DISPOSITION],
881                        { "Content-Disposition",                 "sip.Content-Disposition", 
882                        FT_STRING, BASE_NONE,NULL,0x0,
883                         "RFC 3261: Content-Disposition Header", HFILL }
884                 },
885                 { &hf_header_array[POS_CONTENT_ENCODING],
886                        { "Content-Encoding",            "sip.Content-Encoding", 
887                        FT_STRING, BASE_NONE,NULL,0x0,
888                         "RFC 3261: Content-Encoding Header", HFILL }
889                 },
890                 { &hf_header_array[POS_CONTENT_LANGUAGE],
891                        { "Content-Language",            "sip.Content-Language", 
892                        FT_STRING, BASE_NONE,NULL,0x0,
893                         "RFC 3261: Content-Language Header", HFILL }
894                 },
895                 { &hf_header_array[POS_CONTENT_LENGTH],
896                        { "Content-Length",              "sip.Content-Length", 
897                        FT_STRING, BASE_NONE,NULL,0x0,
898                         "RFC 3261: Content-Length Header", HFILL }
899                 },
900                 { &hf_header_array[POS_CONTENT_TYPE],
901                        { "Content-Type",                "sip.Content-Type", 
902                        FT_STRING, BASE_NONE,NULL,0x0,
903                         "RFC 3261: Content-Type Header", HFILL }
904                 },
905                 { &hf_header_array[POS_CSEQ],
906                        { "CSeq",                "sip.CSeq", 
907                        FT_STRING, BASE_NONE,NULL,0x0,
908                         "RFC 3261: CSeq Header", HFILL }
909                 },
910                 { &hf_header_array[POS_DATE],
911                        { "Date",                "sip.Date", 
912                        FT_STRING, BASE_NONE,NULL,0x0,
913                         "RFC 3261: Date Header", HFILL }
914                 },
915                 { &hf_header_array[POS_ERROR_INFO],
916                        { "Error-Info",          "sip.Error-Info", 
917                        FT_STRING, BASE_NONE,NULL,0x0,
918                         "RFC 3261: Error-Info Header", HFILL }
919                 },
920                 { &hf_header_array[POS_EVENT],
921                        { "Event",               "sip.Event", 
922                        FT_STRING, BASE_NONE,NULL,0x0,
923                         "RFC 3265: Event Header", HFILL }
924                 },
925                 { &hf_header_array[POS_EXPIRES],
926                        { "Expires",             "sip.Expires", 
927                        FT_STRING, BASE_NONE,NULL,0x0,
928                         "RFC 3261: Expires Header", HFILL }
929                 },
930                 { &hf_header_array[POS_FROM],
931                        { "From",                "sip.From", 
932                        FT_STRING, BASE_NONE,NULL,0x0,
933                         "RFC 3261: From Header", HFILL }
934                 },
935                 { &hf_header_array[POS_IN_REPLY_TO],
936                        { "In-Reply-To",                 "sip.In-Reply-To", 
937                        FT_STRING, BASE_NONE,NULL,0x0,
938                         "RFC 3261: In-Reply-To Header", HFILL }
939                 },
940                 { &hf_header_array[POS_MAX_FORWARDS],
941                        { "Max-Forwards",                "sip.Max-Forwards", 
942                        FT_STRING, BASE_NONE,NULL,0x0,
943                         "RFC 3261: Max-Forwards Header", HFILL }
944                 },
945                 { &hf_header_array[POS_MIME_VERSION],
946                        { "MIME-Version",                "sip.MIME-Version", 
947                        FT_STRING, BASE_NONE,NULL,0x0,
948                         "RFC 3261: MIME-Version Header", HFILL }
949                 },
950                 { &hf_header_array[POS_MIN_EXPIRES],
951                        { "Min-Expires",                 "sip.Min-Expires", 
952                        FT_STRING, BASE_NONE,NULL,0x0,
953                         "RFC 3261: Min-Expires Header", HFILL }
954                 },
955                 { &hf_header_array[POS_ORGANIZATION],
956                        { "Organization",                "sip.Organization", 
957                        FT_STRING, BASE_NONE,NULL,0x0,
958                         "RFC 3261: Organization Header", HFILL }
959                 },
960                 { &hf_header_array[POS_PRIORITY],
961                        { "Priority",            "sip.Priority", 
962                        FT_STRING, BASE_NONE,NULL,0x0,
963                         "RFC 3261: Priority Header", HFILL }
964                 },
965                 { &hf_header_array[POS_PROXY_AUTHENTICATE],
966                        { "Proxy-Authenticate",          "sip.Proxy-Authenticate", 
967                        FT_STRING, BASE_NONE,NULL,0x0,
968                         "RFC 3261: Proxy-Authenticate Header", HFILL }
969                 },
970                 { &hf_header_array[POS_PROXY_AUTHORIZATION],
971                        { "Proxy-Authorization",                 "sip.Proxy-Authorization", 
972                        FT_STRING, BASE_NONE,NULL,0x0,
973                         "RFC 3261: Proxy-Authorization Header", HFILL }
974                 },
975                 { &hf_header_array[POS_RACK],
976                        { "RAck",                "sip.RAck", 
977                        FT_STRING, BASE_NONE,NULL,0x0,
978                         "RFC 3262: RAck Header", HFILL }
979                 },
980                 { &hf_header_array[POS_RSEQ],
981                        { "RSeq",                "sip.RSeq", 
982                        FT_STRING, BASE_NONE,NULL,0x0,
983                         "RFC 3262: RSeq Header", HFILL }
984                 },
985                 { &hf_header_array[POS_PROXY_REQUIRE],
986                        { "Proxy-Require",               "sip.Proxy-Require", 
987                        FT_STRING, BASE_NONE,NULL,0x0,
988                         "RFC 3261: Proxy-Require Header", HFILL }
989                 },
990                 { &hf_header_array[POS_RECORD_ROUTE],
991                        { "Record-Route",                "sip.Record-Route", 
992                        FT_STRING, BASE_NONE,NULL,0x0,
993                         "RFC 3261: Record-Route Header", HFILL }
994                 },
995                 { &hf_header_array[POS_REPLY_TO],
996                        { "Reply-To",            "sip.Reply-To", 
997                        FT_STRING, BASE_NONE,NULL,0x0,
998                         "RFC 3261: Reply-To Header", HFILL }
999                 },
1000                 { &hf_header_array[POS_REQUIRE],
1001                        { "Require",             "sip.Require", 
1002                        FT_STRING, BASE_NONE,NULL,0x0,
1003                         "RFC 3261: Require Header", HFILL }
1004                 },
1005                 { &hf_header_array[POS_RETRY_AFTER],
1006                        { "Retry-After",                 "sip.Retry-After", 
1007                        FT_STRING, BASE_NONE,NULL,0x0,
1008                         "RFC 3261: Retry-After Header", HFILL }
1009                 },
1010                 { &hf_header_array[POS_ROUTE],
1011                        { "Route",               "sip.Route", 
1012                        FT_STRING, BASE_NONE,NULL,0x0,
1013                         "RFC 3261: Route Header", HFILL }
1014                 },
1015                 { &hf_header_array[POS_SERVER],
1016                        { "Server",              "sip.Server", 
1017                        FT_STRING, BASE_NONE,NULL,0x0,
1018                         "RFC 3261: Server Header", HFILL }
1019                 },
1020                 { &hf_header_array[POS_SUBJECT],
1021                        { "Subject",             "sip.Subject", 
1022                        FT_STRING, BASE_NONE,NULL,0x0,
1023                         "RFC 3261: Subject Header", HFILL }
1024                 },
1025                 { &hf_header_array[POS_SUBSCRIPTION_STATE],
1026                        { "Subscription-State",          "sip.Subscription-State", 
1027                        FT_STRING, BASE_NONE,NULL,0x0,
1028                         "RFC 3265: Subscription-State Header", HFILL }
1029                 },
1030                 { &hf_header_array[POS_SUPPORTED],
1031                        { "Supported",           "sip.Supported", 
1032                        FT_STRING, BASE_NONE,NULL,0x0,
1033                         "RFC 3261: Supported Header", HFILL }
1034                 },
1035                 { &hf_header_array[POS_TIMESTAMP],
1036                        { "Timestamp",           "sip.Timestamp", 
1037                        FT_STRING, BASE_NONE,NULL,0x0,
1038                         "RFC 3261: Timestamp Header", HFILL }
1039                 },
1040                 { &hf_header_array[POS_TO],
1041                        { "To",          "sip.To", 
1042                        FT_STRING, BASE_NONE,NULL,0x0,
1043                         "RFC 3261: To Header", HFILL }
1044                 },
1045                 { &hf_header_array[POS_UNSUPPORTED],
1046                        { "Unsupported",                 "sip.Unsupported", 
1047                        FT_STRING, BASE_NONE,NULL,0x0,
1048                         "RFC 3261: Unsupported Header", HFILL }
1049                 },
1050                 { &hf_header_array[POS_USER_AGENT],
1051                        { "User-Agent",          "sip.User-Agent", 
1052                        FT_STRING, BASE_NONE,NULL,0x0,
1053                         "RFC 3261: User-Agent Header", HFILL }
1054                 },
1055                 { &hf_header_array[POS_VIA],
1056                        { "Via",                 "sip.Via", 
1057                        FT_STRING, BASE_NONE,NULL,0x0,
1058                         "RFC 3261: Via Header", HFILL }
1059                 },
1060                 { &hf_header_array[POS_WARNING],
1061                        { "Warning",             "sip.Warning", 
1062                        FT_STRING, BASE_NONE,NULL,0x0,
1063                         "RFC 3261: Warning Header", HFILL }
1064                 },
1065                 { &hf_header_array[POS_WWW_AUTHENTICATE],
1066                        { "WWW-Authenticate",            "sip.WWW-Authenticate", 
1067                        FT_STRING, BASE_NONE,NULL,0x0,
1068                         "RFC 3261: WWW-Authenticate Header", HFILL }
1069                 },
1070         };
1071
1072         /* Setup protocol subtree array */
1073         static gint *ett[] = {
1074                 &ett_sip,
1075                 &ett_sip_reqresp,
1076                 &ett_sip_hdr,
1077                 &ett_sip_element,
1078         };
1079
1080         static gint *ett_raw[] = {
1081                 &ett_raw_text,
1082         };
1083
1084           module_t *sip_module;
1085
1086         /* Register the protocol name and description */
1087         proto_sip = proto_register_protocol("Session Initiation Protocol",
1088             "SIP", "sip");
1089         proto_raw_sip = proto_register_protocol("Session Initiation Protocol (SIP as raw text)",
1090             "Raw_SIP", "raw_sip");
1091
1092         /* Required function calls to register the header fields and subtrees used */
1093         proto_register_field_array(proto_sip, hf, array_length(hf));
1094         proto_register_subtree_array(ett, array_length(ett));
1095         proto_register_subtree_array(ett_raw, array_length(ett_raw));
1096
1097         sip_module = prefs_register_protocol(proto_sip, NULL);
1098
1099         prefs_register_bool_preference(sip_module, "display_raw_text",
1100                 "Display raw text for SIP message",
1101                 "Specifies that the raw text of the "
1102                 "SIP message should be displayed "
1103                 "in addition to the dissection tree",
1104                 &global_sip_raw_text);
1105 }
1106
1107 void
1108 proto_reg_handoff_sip(void)
1109 {
1110         dissector_handle_t sip_handle, sip_tcp_handle;
1111
1112         sip_handle = new_create_dissector_handle(dissect_sip, proto_sip);
1113         dissector_add("udp.port", UDP_PORT_SIP, sip_handle);
1114
1115         sip_tcp_handle = create_dissector_handle(dissect_sip_tcp, proto_sip);
1116         dissector_add("tcp.port", TCP_PORT_SIP, sip_tcp_handle);
1117
1118         heur_dissector_add("udp", dissect_sip_heur, proto_sip);
1119         heur_dissector_add("tcp", dissect_sip_heur, proto_sip);
1120         heur_dissector_add("sctp", dissect_sip_heur, proto_sip);
1121
1122         /*
1123          * Get a handle for the SDP dissector.
1124          */
1125         sdp_handle = find_dissector("sdp");
1126 }