2 * Routines for the Session Initiation Protocol (SIP) dissection.
5 * TODO: Pay attention to Content-Type: It might not always be SDP.
6 * Content-Type is fixed, mixed/mode is not handled though.
7 * hf_ display filters for headers of SIP extension RFCs:
8 * Done for RFC 3265, RFC 3262
9 * Use hash table for list of headers
10 * Add sip msg body dissection based on Content-Type for:
11 * SDP, MIME, and other types
12 * Align SIP methods with recent Internet Drafts or RFC
13 * (SIP INFO, rfc2976 - done)
14 * (SIP SUBSCRIBE-NOTIFY - done)
18 * Copyright 2000, Heikki Vatiainen <hessu@cs.tut.fi>
19 * Copyright 2001, Jean-Francois Mule <jfm@cablelabs.com>
20 * Copyright 2004, Anders Broman <anders.broman@ericsson.com>
24 * Ethereal - Network traffic analyzer
25 * By Gerald Combs <gerald@ethereal.com>
26 * Copyright 1998 Gerald Combs
28 * Copied from packet-cops.c
30 * This program is free software; you can redistribute it and/or
31 * modify it under the terms of the GNU General Public License
32 * as published by the Free Software Foundation; either version 2
33 * of the License, or (at your option) any later version.
35 * This program is distributed in the hope that it will be useful,
36 * but WITHOUT ANY WARRANTY; without even the implied warranty of
37 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
38 * GNU General Public License for more details.
40 * You should have received a copy of the GNU General Public License
41 * along with this program; if not, write to the Free Software
42 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
54 #include <epan/prefs.h>
57 #include <epan/packet.h>
59 #include "packet-sip.h"
62 #define TCP_PORT_SIP 5060
63 #define UDP_PORT_SIP 5060
65 static gint sip_tap = -1;
66 static dissector_handle_t sigcomp_handle;
68 /* Initial size of hash table tracking state of calls */
69 #define SIP_INIT_HASH_TABLE_SIZE 50
71 /* Initialize the protocol and registered fields */
72 static gint proto_sip = -1;
73 static gint proto_raw_sip = -1;
74 static gint hf_msg_hdr = -1;
75 static gint hf_Method = -1;
76 static gint hf_Request_Line = -1;
77 static gint hf_Status_Code = -1;
78 static gint hf_Status_Line = -1;
79 static gint hf_sip_display = -1;
80 static gint hf_sip_to_addr = -1;
81 static gint hf_sip_from_addr = -1;
82 static gint hf_sip_tag = -1;
83 static gint hf_sip_uri = -1;
84 static gint hf_sip_contact_addr = -1;
85 static gint hf_sip_contact_item = -1;
86 static gint hf_sip_resend = -1;
87 static gint hf_sip_original_frame = -1;
89 /* Initialize the subtree pointers */
90 static gint ett_sip = -1;
91 static gint ett_sip_reqresp = -1;
92 static gint ett_sip_hdr = -1;
93 static gint ett_raw_text = -1;
94 static gint ett_sip_element = -1;
95 static gint ett_sip_uri = -1;
96 static gint ett_sip_contact_item = -1;
97 static gint ett_sip_message_body = -1;
99 /* PUBLISH method added as per http://www.ietf.org/internet-drafts/draft-ietf-sip-publish-01.txt */
100 static const char *sip_methods[] = {
101 "<Invalid method>", /* Pad so that the real methods start at index 1 */
122 * Updated with info from http://www.iana.org/assignments/sip-parameters
123 * (last updated 2004-10-17)
124 * Updated with: http://www.ietf.org/internet-drafts/draft-ietf-sip-resource-priority-05.txt
130 static const sip_header_t sip_headers[] = {
131 { "Unknown-header", NULL }, /* 0 Pad so that the real headers start at index 1 */
132 { "Accept", NULL }, /* 1 */
133 { "Accept-Contact", "a" }, /* 2 RFC3841 */
134 { "Accept-Encoding", NULL }, /* 3 */
135 { "Accept-Language", NULL }, /* 4 */
136 { "Accept-Resource-Priority", NULL }, /* 5 draft-ietf-sip-resource-priority-05.txt */
137 { "Alert-Info", NULL },
139 { "Allow-Events", "u" }, /* 8 RFC3265 */
140 { "Authentication-Info", NULL },
141 { "Authorization", NULL }, /* 10 */
143 { "Call-Info", NULL },
145 { "Content-Disposition", NULL },
146 { "Content-Encoding", "e" }, /* 15 */
147 { "Content-Language", NULL },
148 { "Content-Length", "l" },
149 { "Content-Type", "c" },
151 { "Date", NULL }, /* 20 */
152 { "Error-Info", NULL },
156 { "In-Reply-To", NULL }, /* 25 RFC3261 */
157 { "Join", NULL }, /* 26 RFC-ietf-sip-join-03.txt */
158 { "Max-Forwards", NULL },
159 { "MIME-Version", NULL },
160 { "Min-Expires", NULL },
161 { "Min-SE", NULL }, /* 30 RFC-ietf-sip-session-timer-15.txt */
162 { "Organization", NULL },
163 { "P-Access-Network-Info", NULL }, /* 32 RFC3455 */
164 { "P-Asserted-Identity", NULL }, /* 33 RFC3325 */
165 { "P-Associated-URI", NULL }, /* 34 RFC3455 */
166 { "P-Called-Party-ID", NULL }, /* 35 RFC3455 */
167 { "P-Charging-Function-Addresses",NULL },/* 36 RFC3455 */
168 { "P-Charging-Vector", NULL }, /* 37 RFC3455 */
169 { "P-DCS-Trace-Party-ID", NULL }, /* 38 RFC3603 */
170 { "P-DCS-OSPS", NULL }, /* 39 RFC3603 */
171 { "P-DCS-Billing-Info", NULL }, /* 40 RFC3603 */
172 { "P-DCS-LAES", NULL }, /* 41 RFC3603 */
173 { "P-DCS-Redirect", NULL }, /* 42 RFC3603 */
174 { "P-Media-Authorization", NULL }, /* 43 RFC3313 */
175 { "P-Preferred-Identity", NULL }, /* 44 RFC3325 */
176 { "P-Visited-Network-ID", NULL }, /* 45 RFC3455 */
177 { "Path", NULL }, /* 46 RFC3327 */
178 { "Priority", NULL },
179 { "Privacy", NULL }, /* 48 RFC3323 */
180 { "Proxy-Authenticate", NULL },
181 { "Proxy-Authorization", NULL }, /* 50 */
182 { "Proxy-Require", NULL },
184 { "Reason", NULL }, /* 53 RFC3326 */
185 { "Record-Route", NULL },
186 { "Referred-By", "b" }, /* 55 RFC3892 */
187 { "Reject-Contact", "j" }, /* 56 RFC3841 */
188 { "Replaces", NULL }, /* 57 RFC3891 */
189 { "Reply-To", NULL }, /* 58 RFC3261 */
190 { "Request-Disposition", "d" }, /* 59 RFC3841 */
191 { "Require", NULL }, /* 60 RFC3261 */
192 { "Resource-Priority", NULL }, /* 61 draft-ietf-sip-resource-priority-05.txt */
193 { "Retry-After", NULL }, /* 62 RFC3261 */
194 { "Route", NULL }, /* 63 RFC3261 */
195 { "RSeq", NULL }, /* 64 RFC3841 */
196 { "Security-Client", NULL }, /* 65 RFC3329 */
197 { "Security-Server", NULL }, /* 66 RFC3329 */
198 { "Security-Verify", NULL }, /* 67 RFC3329 */
199 { "Server", NULL }, /* 68 RFC3261 */
200 { "Service-Route", NULL }, /* 69 RFC3608 */
201 { "Session-Expires", "x" }, /* 70 RFC-ietf-sip-session-timer-15.txt */
202 { "SIP-ETag", NULL }, /* 71 draft-ietf-sip-publish-03 */
203 { "SIP-If-Match", NULL }, /* 72 draft-ietf-sip-publish-03 */
204 { "Subject", "s" }, /* 73 RFC3261 */
205 { "Subscription-State", NULL }, /* 74 RFC3265 */
206 { "Supported", "k" }, /* 75 RFC3261 */
207 { "Timestamp", NULL }, /* 76 RFC3261 */
208 { "To", "t" }, /* 77 RFC3261 */
209 { "Unsupported", NULL }, /* 78 RFC3261 */
210 { "User-Agent", NULL }, /* 79 RFC3261 */
211 { "Via", "v" }, /* 80 RFC3261 */
212 { "Warning", NULL }, /* 81 RFC3261 */
213 { "WWW-Authenticate", NULL }, /* 82 RFC3261 */
214 { "Refer-To", "r" }, /* 83 RFC3515 */
220 #define POS_ACCEPT_CONTACT 2
221 #define POS_ACCEPT_ENCODING 3
222 #define POS_ACCEPT_LANGUAGE 4
223 #define POS_ACCEPT_RESOURCE_PRIORITY 5
224 #define POS_ALERT_INFO 6
226 #define POS_ALLOW_EVENTS 8
227 #define POS_AUTHENTICATION_INFO 9
228 #define POS_AUTHORIZATION 10
229 #define POS_CALL_ID 11
230 #define POS_CALL_INFO 12
231 #define POS_CONTACT 13
232 #define POS_CONTENT_DISPOSITION 14
233 #define POS_CONTENT_ENCODING 15
234 #define POS_CONTENT_LANGUAGE 16
235 #define POS_CONTENT_LENGTH 17
236 #define POS_CONTENT_TYPE 18
239 #define POS_ERROR_INFO 21
241 #define POS_EXPIRES 23
243 #define POS_IN_REPLY_TO 25
245 #define POS_MAX_FORWARDS 27
246 #define POS_MIME_VERSION 28
247 #define POS_MIN_EXPIRES 29
248 #define POS_MIN_SE 30
249 #define POS_ORGANIZATION 31
250 #define POS_P_ACCESS_NETWORK_INFO 32
251 #define POS_P_ASSERTED_IDENTITY 33
252 #define POS_P_ASSOCIATED_URI 34
253 #define POS_P_CALLED_PARTY_ID 35
254 #define POS_P_CHARGING_FUNCTION_ADDRESSES 36
255 #define POS_P_CHARGING_VECTOR 37
256 #define POS_P_DCS_TRACE_PARTY_ID 38
257 #define POS_P_DCS_OSPS 39
258 #define POS_P_DCS_BILLING_INFO 40
259 #define POS_P_DCS_LAES 41
260 #define POS_P_DCS_REDIRECT 42
261 #define POS_P_MEDIA_AUTHORIZATION 43
262 #define POS_P_PREFERRED_IDENTITY 44
263 #define POS_P_VISITED_NETWORK_ID 45
265 #define POS_PRIORITY 47
266 #define POS_PRIVACY 48
267 #define POS_PROXY_AUTHENTICATE 49
268 #define POS_PROXY_AUTHORIZATION 50
269 #define POS_PROXY_REQUIRE 51
271 #define POS_REASON 53
272 #define POS_RECORD_ROUTE 54
273 #define POS_REFERED_BY 55
274 #define POS_REJECT_CONTACT 56
275 #define POS_REPLACES 57
276 #define POS_REPLY_TO 58
277 #define POS_REQUEST_DISPOSITION 59
278 #define POS_REQUIRE 60
279 #define POS_RESOURCE_PRIORITY 61
280 #define POS_RETRY_AFTER 62
283 #define POS_SECURITY_CLIENT 65
284 #define POS_SECURITY_SERVER 66
285 #define POS_SECURITY_VERIFY 67
286 #define POS_SERVER 68
287 #define POS_SERVICE_ROUTE 69
288 #define POS_SESSION_EXPIRES 70
289 #define POS_SIP_ETAG 71
290 #define POS_SIP_IF_MATCH 72
291 #define POS_SUBJECT 73
292 #define POS_SUBSCRIPTION_STATE 74
293 #define POS_SUPPORTED 75
294 #define POS_TIMESTAMP 76
296 #define POS_UNSUPPORTED 78
297 #define POS_USER_AGENT 79
299 #define POS_WARNING 81
300 #define POS_WWW_AUTHENTICATE 82
301 #define POS_REFER_TO 83
303 static gint hf_header_array[] = {
304 -1, /* 0"Unknown-header" - Pad so that the real headers start at index 1 */
306 -1, /* 2"Accept-Contact" RFC3841 */
307 -1, /* 3"Accept-Encoding" */
308 -1, /* 4"Accept-Language" */
309 -1, /* 5"Accept-Resource-Priority" draft-ietf-sip-resource-priority-05.txt */
310 -1, /* 6"Alert-Info", */
312 -1, /* 8"Allow-Events", RFC3265 */
313 -1, /* 9"Authentication-Info" */
314 -1, /* 10"Authorization", */
315 -1, /* 11"Call-ID", */
316 -1, /* 12"Call-Info" */
317 -1, /* 13"Contact", */
318 -1, /* 14"Content-Disposition", */
319 -1, /* 15"Content-Encoding", */
320 -1, /* 16"Content-Language", */
321 -1, /* 17"Content-Length", */
322 -1, /* 18"Content-Type", */
325 -1, /* 21"Error-Info", */
327 -1, /* 23"Expires", */
329 -1, /* 25"In-Reply-To", RFC3261 */
330 -1, /* 26"Join", RFC-ietf-sip-join-03.txt */
331 -1, /* 27"Max-Forwards", */
332 -1, /* 28"MIME-Version", */
333 -1, /* 29"Min-Expires", */
334 -1, /* 30"Min-SE", RFC-ietf-sip-session-timer-15.txt */
335 -1, /* 31"Organization", */
336 -1, /* 32"P-Access-Network-Info", RFC3455 */
337 -1, /* 33"P-Asserted-Identity", RFC3325 */
338 -1, /* 34"P-Associated-URI", RFC3455 */
339 -1, /* 35"P-Called-Party-ID", RFC3455 */
340 -1, /* 36"P-Charging-Function-Addresses", RFC3455 */
341 -1, /* 37"P-Charging-Vector", RFC3455 */
342 -1, /* 38"P-DCS-Trace-Party-ID", RFC3603 */
343 -1, /* 39"P-DCS-OSPS", RFC3603 */
344 -1, /* 40"P-DCS-Billing-Info", RFC3603 */
345 -1, /* 41"P-DCS-LAES", RFC3603 */
346 -1, /* 42"P-DCS-Redirect", RFC3603 */
347 -1, /* 43"P-Media-Authorization", RFC3313 */
348 -1, /* 44"P-Preferred-Identity", RFC3325 */
349 -1, /* 45"P-Visited-Network-ID", RFC3455 */
350 -1, /* 46"Path", RFC3327 */
351 -1, /* 47"Priority" */
352 -1, /* 48"Privacy", RFC3323 */
353 -1, /* 49"Proxy-Authenticate", */
354 -1, /* 50"Proxy-Authorization", */
355 -1, /* 51"Proxy-Require", */
357 -1, /* 53"Reason", RFC3326 */
358 -1, /* 54"Record-Route", */
359 -1, /* 55"Referred-By", */
360 -1, /* 56"Reject-Contact", RFC3841 */
361 -1, /* 57"Replaces", RFC3891 */
362 -1, /* 58"Reply-To", RFC3261 */
363 -1, /* 59"Request-Disposition", RFC3841 */
364 -1, /* 60"Require", RFC3261 */
365 -1, /* 61"Resource-Priority",draft-ietf-sip-resource-priority-05.txt */
366 -1, /* 62"Retry-After", RFC3261 */
367 -1, /* 63"Route", RFC3261 */
368 -1, /* 64"RSeq", RFC3841 */
369 -1, /* 65"Security-Client", RFC3329 */
370 -1, /* 66"Security-Server", RFC3329 */
371 -1, /* 67"Security-Verify", RFC3329 */
372 -1, /* 68"Server", RFC3261 */
373 -1, /* 69"Service-Route", RFC3608 */
374 -1, /* 70"Session-Expires", RFC-ietf-sip-session-timer-15.txt */
375 -1, /* 71"SIP-ETag", draft-ietf-sip-publish-04 */
376 -1, /* 72"SIP-If-Match", draft-ietf-sip-publish-04 */
377 -1, /* 73"Subject", RFC3261 */
378 -1, /* 74"Subscription-State", RFC3265 */
379 -1, /* 75"Supported", RFC3261 */
380 -1, /* 76"Timestamp", RFC3261 */
381 -1, /* 77"To", RFC3261 */
382 -1, /* 78"Unsupported", RFC3261 */
383 -1, /* 79"User-Agent", RFC3261 */
384 -1, /* 80"Via", RFC3261 */
385 -1, /* 81"Warning", RFC3261 */
386 -1, /* 82"WWW-Authenticate", RFC3261 */
387 -1, /* 83"Refer-To", RFC3515 */
392 * Type of line. It's either a SIP Request-Line, a SIP Status-Line, or
393 * another type of line.
401 /* global_sip_raw_text determines whether we are going to display */
402 /* the raw text of the SIP message, much like the MEGACO dissector does. */
403 static gboolean global_sip_raw_text = FALSE;
404 /* strict_sip_version determines whether the SIP dissector enforces
405 * the SIP version to be "SIP/2.0". */
406 static gboolean strict_sip_version = TRUE;
408 static gboolean dissect_sip_common(tvbuff_t *tvb, packet_info *pinfo,
409 proto_tree *tree, gboolean is_heur);
410 static line_type_t sip_parse_line(tvbuff_t *tvb, gint linelen,
412 static gboolean sip_is_known_request(tvbuff_t *tvb, int meth_offset,
413 guint meth_len, guint *meth_idx);
414 static gint sip_is_known_sip_header(tvbuff_t *tvb, int offset,
416 static void dfilter_sip_request_line(tvbuff_t *tvb, proto_tree *tree,
418 static void dfilter_sip_status_line(tvbuff_t *tvb, proto_tree *tree);
419 static void tvb_raw_text_add(tvbuff_t *tvb, proto_tree *tree);
420 static guint sip_is_packet_resend(packet_info *pinfo,
423 guchar cseq_number_set, guint32 cseq_number,
424 line_type_t line_type);
427 /* SIP content type and internet media type used by other dissectors
428 * are the same. List of media types from IANA at:
429 * http://www.iana.org/assignments/media-types/index.html */
430 static dissector_table_t media_type_dissector_table;
432 #define SIP2_HDR "SIP/2.0"
433 #define SIP2_HDR_LEN (strlen (SIP2_HDR))
435 /* Store the info needed by the SIP tap for one packet */
436 static sip_info_value_t *stat_info;
438 /* The buffer size for the cseq_method name */
439 #define MAX_CSEQ_METHOD_SIZE 16
441 /****************************************************************************
442 * Conversation-type definitions
444 * For each call, keep track of the current cseq number and state of
445 * transaction, in order to be able to detect retransmissions.
447 * Don't use the conservation mechanism, but instead:
448 * - store with each dissected packet original frame (if any)
449 * - maintain a global hash table of
450 * (call_id, source_addr, dest_addr) -> (cseq, transaction_state, frame)
451 ****************************************************************************/
453 static GHashTable *sip_hash = NULL; /* Hash table */
454 static GMemChunk *sip_hash_keys = NULL; /* Hash key chunk */
455 static GMemChunk *sip_hash_values = NULL; /* Hash value chunk */
457 /* Types for hash table keys and values */
458 #define MAX_CALL_ID_SIZE 128
461 char call_id[MAX_CALL_ID_SIZE];
462 address source_address;
464 address dest_address;
473 provisional_response_seen,
475 } transaction_state_t;
480 transaction_state_t transaction_state;
481 guint32 response_code;
486 /************************/
487 /* Hash table functions */
490 gint sip_equal(gconstpointer v, gconstpointer v2)
492 const sip_hash_key* val1 = v;
493 const sip_hash_key* val2 = v2;
495 /* Call id must match */
496 if (strcmp(val1->call_id, val2->call_id) != 0)
501 /* Addresses must match */
502 return (ADDRESSES_EQUAL(&(val1->source_address), &(val2->source_address))) &&
503 (val1->source_port == val2->source_port) &&
504 (ADDRESSES_EQUAL(&(val1->dest_address), &(val2->dest_address))) &&
505 (val1->dest_port == val2->dest_port);
508 /* Compute a hash value for a given key. */
509 /* Don't try to use addresses here, call-id should be almost unique. */
510 guint sip_hash_func(gconstpointer v)
513 const sip_hash_key *key = v;
514 guint value = strlen(key->call_id);
515 gint chars_to_use = value / 4;
517 /* First few characters from the call-id should be enough... */
518 for (n=0; n < chars_to_use; n++)
520 value += key->call_id[n];
527 /* Initializes the hash table and the mem_chunk area each time a new
528 * file is loaded or re-loaded in ethereal */
530 sip_init_protocol(void)
532 /* Destroy any existing memory chunks / hashes. */
534 g_hash_table_destroy(sip_hash);
536 g_mem_chunk_destroy(sip_hash_keys);
538 g_mem_chunk_destroy(sip_hash_values);
540 /* Now create them over */
541 sip_hash = g_hash_table_new(sip_hash_func, sip_equal);
542 sip_hash_keys = g_mem_chunk_new("sip_hash_keys",
543 sizeof(sip_hash_key),
544 SIP_INIT_HASH_TABLE_SIZE * sizeof(sip_hash_key),
546 sip_hash_values = g_mem_chunk_new("sip_hash_values",
547 sizeof(sip_hash_value),
548 SIP_INIT_HASH_TABLE_SIZE * sizeof(sip_hash_value),
553 * Copied from the mgcp dissector. (This function should be moved to /epan )
554 * tvb_skip_wsp - Returns the position in tvb of the first non-whitespace
555 * character following offset or offset + maxlength -1 whichever
559 * tvb - The tvbuff in which we are skipping whitespace.
560 * offset - The offset in tvb from which we begin trying to skip whitespace.
561 * maxlength - The maximum distance from offset that we may try to skip
564 * Returns: The position in tvb of the first non-whitespace
565 * character following offset or offset + maxlength -1 whichever
568 static gint tvb_skip_wsp(tvbuff_t* tvb, gint offset, gint maxlength)
570 gint counter = offset;
571 gint end = offset + maxlength,tvb_len;
574 /* Get the length remaining */
575 tvb_len = tvb_length(tvb);
576 end = offset + maxlength;
582 /* Skip past spaces and tabs until run out or meet something else */
583 for (counter = offset;
585 ((tempchar = tvb_get_guint8(tvb,counter)) == ' ' ||
592 /* Structure to collect info about a sip uri */
593 typedef struct _uri_offset_info
595 gint display_name_start;
596 gint display_name_end;
599 gint uri_parameters_start;
600 gint uri_parameters_end;
601 gint name_addr_start;
605 /* Code to parse a sip uri.
606 * Returns Offset end off parsing or -1 for unsuccessful parsing
609 dissect_sip_uri(tvbuff_t *tvb, packet_info *pinfo _U_, gint start_offset,
610 gint line_end_offset, uri_offset_info *uri_offsets)
618 gint semicolon_offset;
619 gint question_mark_offset;
620 gboolean uri_without_angle_quotes = FALSE;
622 /* skip Spaces and Tabs */
623 current_offset = tvb_skip_wsp(tvb, start_offset, line_end_offset - start_offset);
625 if(current_offset >= line_end_offset) {
626 /* Nothing to parse */
630 uri_offsets->name_addr_start = current_offset;
632 /* First look, if we have a display name */
633 c=tvb_get_guint8(tvb, current_offset);
637 /* We have a display name, look for the next unescaped '"' */
638 uri_offsets->display_name_start = current_offset;
641 queried_offset = tvb_find_guint8(tvb, current_offset + 1, line_end_offset - (current_offset + 1), '"');
642 if(queried_offset == -1)
647 current_offset = queried_offset;
650 /* count back slashes before '"' */
651 for(i=1;tvb_get_guint8(tvb, queried_offset - i) == '\\';i++);
659 } while (current_offset < line_end_offset);
660 if(current_offset >= line_end_offset)
666 uri_offsets->display_name_end = current_offset;
668 /* find start of the URI */
669 queried_offset = tvb_find_guint8(tvb, current_offset, line_end_offset - current_offset, '<');
670 if(queried_offset == -1)
675 current_offset = queried_offset + 1;
679 /* We don't have a display name */
684 /* We have either an URI without angles or a display name with a limited character set */
685 /* Look for the right angle quote or colon */
686 queried_offset = tvb_find_guint8(tvb, current_offset, line_end_offset - current_offset, '<');
687 colon_offset = tvb_find_guint8(tvb, current_offset, line_end_offset - current_offset, ':');
688 if(queried_offset != -1 && colon_offset != -1)
690 if(queried_offset < colon_offset)
692 /* we have an URI with angle quotes */
693 uri_offsets->display_name_start = current_offset;
694 uri_offsets->display_name_end = queried_offset - 1;
695 current_offset = queried_offset + 1;
699 /* we have an URI without angle quotes */
700 uri_without_angle_quotes = TRUE;
705 if(queried_offset != -1)
707 /* we have an URI with angle quotes */
708 uri_offsets->display_name_start = current_offset;
709 uri_offsets->display_name_end = queried_offset - 1;
710 current_offset = queried_offset + 1;
713 if(colon_offset != -1)
715 /* we have an URI without angle quotes */
716 uri_without_angle_quotes = TRUE;
719 /* If this point is reached, we can't parse the URI */
725 /* Start parsing of URI */
726 uri_offsets->uri_start = current_offset;
727 if(uri_without_angle_quotes == TRUE)
729 /* look for the first ',' or ';' which will mark the end of this URI
730 * In this case a semicolon indicates a header field parameter, and not an uri parameter.
732 comma_offset = tvb_find_guint8(tvb, current_offset, line_end_offset - current_offset, ',');
733 semicolon_offset = tvb_find_guint8(tvb, current_offset, line_end_offset - current_offset, ';');
735 if (semicolon_offset != -1 && comma_offset != -1)
737 if(semicolon_offset < comma_offset)
739 uri_offsets->uri_end = semicolon_offset - 1;
743 uri_offsets->uri_end = comma_offset - 1;
748 if (semicolon_offset != -1)
750 uri_offsets->uri_end = semicolon_offset - 1;
752 if (comma_offset != -1)
754 uri_offsets->uri_end = comma_offset - 1;
756 /* If both offsets are equal to -1, we don't have a semicolon or a comma.
757 * In that case, we assume that the end of the URI is at the line end
759 uri_offsets->uri_end = line_end_offset - 2;
761 uri_offsets->name_addr_end = uri_offsets->uri_end;
762 current_offset = uri_offsets->uri_end + 1; /* Now save current_offset, as it is the value to be returned now */
766 /* look for closing angle quote */
767 queried_offset = tvb_find_guint8(tvb, current_offset, line_end_offset - current_offset, '>');
768 if(queried_offset == -1)
773 uri_offsets->name_addr_end = queried_offset;
774 uri_offsets->uri_end = queried_offset - 1;
775 current_offset = queried_offset; /* Now save current_offset. It contains the value we have to return */
777 /* Look for '@' within URI */
778 queried_offset = tvb_find_guint8(tvb, uri_offsets->uri_start, uri_offsets->uri_end - uri_offsets->uri_start, '@');
779 if(queried_offset == -1)
781 /* no '@': look for the first ';' or '?' in the URI */
782 question_mark_offset = tvb_find_guint8(tvb, uri_offsets->uri_start, uri_offsets->uri_end - uri_offsets->uri_start, '?');
783 semicolon_offset = tvb_find_guint8(tvb, uri_offsets->uri_start, uri_offsets->uri_end - uri_offsets->uri_start, ';');
787 /* with '@': look for the first ';' or '?' behind the '@' */
788 question_mark_offset = tvb_find_guint8(tvb, queried_offset, uri_offsets->uri_end - queried_offset, '?');
789 semicolon_offset = tvb_find_guint8(tvb, queried_offset, uri_offsets->uri_end - queried_offset, ';');
793 if (semicolon_offset != -1 && question_mark_offset != -1)
795 if(semicolon_offset < question_mark_offset)
797 uri_offsets->uri_parameters_start = semicolon_offset;
801 uri_offsets->uri_parameters_start = question_mark_offset;
803 uri_offsets->uri_parameters_end = uri_offsets->uri_end;
804 uri_offsets->uri_end = uri_offsets->uri_parameters_start - 1;
808 if (semicolon_offset != -1)
810 uri_offsets->uri_parameters_start = semicolon_offset;
811 uri_offsets->uri_parameters_end = uri_offsets->uri_end;
812 uri_offsets->uri_end = uri_offsets->uri_parameters_start - 1;
814 if (question_mark_offset != -1)
816 uri_offsets->uri_parameters_start = question_mark_offset;
817 uri_offsets->uri_parameters_end = uri_offsets->uri_end;
818 uri_offsets->uri_end = uri_offsets->uri_parameters_start - 1;
820 /* If both offsets are equal to -1, we don't have a semicolon or a question mark.
821 * In that case, we don't have to save any offsets.
827 return current_offset;
831 /* Code to parse a contact header item
832 * Returns Offset end off parsing or -1 for unsuccessful parsing
835 dissect_sip_contact_item(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint start_offset, gint line_end_offset)
838 proto_item *ti = NULL;
839 proto_tree *contact_item_tree = NULL, *uri_tree = NULL;
843 gint contact_params_start_offset = -1;
844 gint contact_item_end_offset = -1;
845 uri_offset_info uri_offsets;
847 uri_offsets.display_name_start = -1;
848 uri_offsets.display_name_end = -1;
849 uri_offsets.uri_start = -1;
850 uri_offsets.uri_end = -1;
851 uri_offsets.uri_parameters_start = -1;
852 uri_offsets.uri_parameters_end = -1;
853 uri_offsets.name_addr_start = -1;
854 uri_offsets.name_addr_end = -1;
856 /* skip Spaces and Tabs */
857 start_offset = tvb_skip_wsp(tvb, start_offset, line_end_offset - start_offset);
859 if(start_offset >= line_end_offset) {
860 /* Nothing to parse */
864 current_offset = dissect_sip_uri(tvb, pinfo, start_offset, line_end_offset, &uri_offsets);
865 if(current_offset == -1)
871 /* Now look for the end of the contact item */
872 while (current_offset < line_end_offset)
874 c=tvb_get_guint8(tvb, current_offset);
876 if(c == ';' && contact_params_start_offset == -1)
878 /* here we start with contact parameters */
879 contact_params_start_offset = current_offset;
884 /* look for the next unescaped '"' */
887 queried_offset = tvb_find_guint8(tvb, current_offset + 1, line_end_offset - (current_offset + 1), '"');
888 if(queried_offset == -1)
893 current_offset = queried_offset;
896 } while (tvb_get_guint8(tvb, queried_offset - 1) == '\\');
901 /* end of contact item found. */
902 contact_item_end_offset = current_offset - 1; /* remove ',' */
909 if(contact_item_end_offset == -1)
910 contact_item_end_offset = line_end_offset - 3; /* remove '\r\n' */
912 /* Build the tree, now */
915 ti = proto_tree_add_string(tree, hf_sip_contact_item, tvb, start_offset, contact_item_end_offset - start_offset + 1,
916 tvb_format_text(tvb, start_offset, contact_item_end_offset - start_offset + 1));
917 contact_item_tree = proto_item_add_subtree(ti, ett_sip_contact_item);
919 ti = proto_tree_add_string(contact_item_tree, hf_sip_uri, tvb, uri_offsets.name_addr_start, uri_offsets.name_addr_end - uri_offsets.name_addr_start + 1,
920 tvb_format_text(tvb, uri_offsets.name_addr_start, uri_offsets.name_addr_end - uri_offsets.name_addr_start + 1));
921 uri_tree = proto_item_add_subtree(ti, ett_sip_uri);
923 if(uri_offsets.display_name_start != -1 && uri_offsets.display_name_end != -1)
925 proto_tree_add_string(uri_tree, hf_sip_display, tvb, uri_offsets.display_name_start,
926 uri_offsets.display_name_end - uri_offsets.display_name_start + 1,
927 tvb_format_text(tvb, uri_offsets.display_name_start,
928 uri_offsets.display_name_end - uri_offsets.display_name_start + 1));
931 if(uri_offsets.uri_start != -1 && uri_offsets.uri_end != -1)
933 proto_tree_add_string(uri_tree, hf_sip_contact_addr, tvb, uri_offsets.uri_start,
934 uri_offsets.uri_end - uri_offsets.uri_start + 1,
935 tvb_format_text(tvb, uri_offsets.uri_start,
936 uri_offsets.uri_end - uri_offsets.uri_start + 1));
939 /* Parse URI and Contact header Parameters now */
943 return current_offset;
946 /* Code to actually dissect the packets */
948 dissect_sip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
952 octet = tvb_get_guint8(tvb,0);
953 if ((octet & 0xf8) == 0xf8){
954 call_dissector(sigcomp_handle, tvb, pinfo, tree);
955 return tvb_length(tvb);
959 if (!dissect_sip_common(tvb, pinfo, tree, FALSE))
962 return tvb_length(tvb);
966 dissect_sip_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
970 octet = tvb_get_guint8(tvb,0);
971 if ((octet & 0xf8) == 0xf8){
972 call_dissector(sigcomp_handle, tvb, pinfo, tree);
975 dissect_sip_common(tvb, pinfo, tree, TRUE);
979 dissect_sip_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
981 return dissect_sip_common(tvb, pinfo, tree, FALSE);
985 dissect_sip_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
986 gboolean dissect_other_as_continuation)
989 gint next_offset, linelen;
990 line_type_t line_type;
992 gboolean is_known_request;
993 gboolean found_match = FALSE;
995 guint token_1_len = 0;
996 guint current_method_idx = 0;
997 proto_item *ts = NULL, *ti = NULL, *th = NULL, *sip_element_item = NULL;
998 proto_tree *sip_tree = NULL, *reqresp_tree = NULL , *hdr_tree = NULL, *sip_element_tree = NULL, *message_body_tree = NULL;
999 guchar contacts = 0, contact_is_star = 0, expires_is_0 = 0;
1000 guint32 cseq_number = 0;
1001 guchar cseq_number_set = 0;
1002 char cseq_method[MAX_CSEQ_METHOD_SIZE] = "";
1003 char call_id[MAX_CALL_ID_SIZE] = "";
1004 char *media_type_str = NULL;
1005 char *media_type_str_lower_case = NULL;
1006 char *content_type_parameter_str = NULL;
1007 guint resend_for_packet = 0;
1011 /* Initialise stat info for passing to tap */
1012 stat_info = g_malloc(sizeof(sip_info_value_t));
1013 stat_info->response_code = 0;
1014 stat_info->request_method = NULL;
1015 stat_info->reason_phrase = NULL;
1016 stat_info->resend = 0;
1017 stat_info->tap_call_id = NULL;
1018 stat_info->tap_from_addr = NULL;
1019 stat_info->tap_to_addr = NULL;
1022 * Note that "tvb_find_line_end()" will return a value that
1023 * is not longer than what's in the buffer, so the
1024 * "tvb_get_ptr()" calls below won't throw exceptions.
1026 * Note that "tvb_strneql()" doesn't throw exceptions, so
1027 * "sip_parse_line()" won't throw an exception.
1030 linelen = tvb_find_line_end(tvb, 0, -1, &next_offset, FALSE);
1031 line_type = sip_parse_line(tvb, linelen, &token_1_len);
1032 if (line_type == OTHER_LINE) {
1034 * This is neither a SIP request nor response.
1036 if (!dissect_other_as_continuation) {
1038 * We were asked to reject this.
1044 * Just dissect it as a continuation.
1048 if (check_col(pinfo->cinfo, COL_PROTOCOL))
1049 col_set_str(pinfo->cinfo, COL_PROTOCOL, "SIP");
1051 switch (line_type) {
1054 is_known_request = sip_is_known_request(tvb, 0, token_1_len, ¤t_method_idx);
1055 descr = is_known_request ? "Request" : "Unknown request";
1056 if (check_col(pinfo->cinfo, COL_INFO)) {
1057 col_add_fstr(pinfo->cinfo, COL_INFO, "%s: %s",
1059 tvb_format_text(tvb, 0, linelen - SIP2_HDR_LEN - 1));
1065 if (check_col(pinfo->cinfo, COL_INFO)) {
1066 col_add_fstr(pinfo->cinfo, COL_INFO, "Status: %s",
1067 tvb_format_text(tvb, SIP2_HDR_LEN + 1, linelen - SIP2_HDR_LEN - 1));
1069 string = tvb_get_string(tvb, SIP2_HDR_LEN + 5, linelen - (SIP2_HDR_LEN + 5));
1070 stat_info->reason_phrase = g_malloc(linelen - (SIP2_HDR_LEN + 5) + 1);
1071 strncpy(stat_info->reason_phrase, string, linelen - (SIP2_HDR_LEN + 5) + 1);
1072 /* String no longer needed */
1077 default: /* Squelch compiler complaints */
1078 descr = "Continuation";
1079 if (check_col(pinfo->cinfo, COL_INFO))
1080 col_set_str(pinfo->cinfo, COL_INFO, "Continuation");
1085 ts = proto_tree_add_item(tree, proto_sip, tvb, 0, -1, FALSE);
1086 sip_tree = proto_item_add_subtree(ts, ett_sip);
1089 switch (line_type) {
1093 ti = proto_tree_add_string(sip_tree, hf_Request_Line, tvb, 0, linelen,
1094 tvb_format_text(tvb, 0, linelen));
1095 reqresp_tree = proto_item_add_subtree(ti, ett_sip_reqresp);
1097 dfilter_sip_request_line(tvb, reqresp_tree, token_1_len);
1102 ti = proto_tree_add_string(sip_tree, hf_Status_Line, tvb, 0, linelen,
1103 tvb_format_text(tvb, 0, linelen));
1104 reqresp_tree = proto_item_add_subtree(ti, ett_sip_reqresp);
1106 dfilter_sip_status_line(tvb, reqresp_tree);
1111 ti = proto_tree_add_text(sip_tree, tvb, 0, next_offset,
1112 "%s line: %s", descr,
1113 tvb_format_text(tvb, 0, linelen));
1114 reqresp_tree = proto_item_add_subtree(ti, ett_sip_reqresp);
1115 proto_tree_add_text(sip_tree, tvb, 0, -1,
1116 "Continuation data");
1121 offset = next_offset;
1123 th = proto_tree_add_item(sip_tree, hf_msg_hdr, tvb, offset, -1, FALSE);
1124 hdr_tree = proto_item_add_subtree(th, ett_sip_hdr);
1128 * Process the headers - if we're not building a protocol tree,
1129 * we just do this to find the blank line separating the
1130 * headers from the message body.
1132 next_offset = offset;
1133 while (tvb_reported_length_remaining(tvb, offset) > 0) {
1134 gint line_end_offset;
1136 gint semi_colon_offset;
1138 gint parameter_offset;
1139 gint parameter_end_offset;
1141 gint content_type_len, content_type_parameter_str_len;
1150 linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE);
1153 * This is a blank line separating the
1154 * message header from the message body.
1158 line_end_offset = offset + linelen;
1159 colon_offset = tvb_find_guint8(tvb, offset, linelen, ':');
1160 if (colon_offset == -1) {
1162 * Malformed header - no colon after the name.
1165 proto_tree_add_text(hdr_tree, tvb, offset,
1166 next_offset - offset, "%s",
1167 tvb_format_text(tvb, offset, linelen));
1170 header_len = colon_offset - offset;
1171 hf_index = sip_is_known_sip_header(tvb, offset, header_len);
1173 if (hf_index == -1) {
1175 proto_tree_add_text(hdr_tree, tvb,
1176 offset, next_offset - offset, "%s",
1177 tvb_format_text(tvb, offset, linelen));
1181 * Skip whitespace after the colon.
1183 value_offset = colon_offset + 1;
1184 while (value_offset < line_end_offset &&
1185 ((c = tvb_get_guint8(tvb, value_offset)) == ' ' ||
1191 value_len = line_end_offset - value_offset;
1192 value = tvb_get_string(tvb, value_offset,
1196 * Add it to the protocol tree,
1197 * but display the line as is.
1199 switch ( hf_index ) {
1203 sip_element_item = proto_tree_add_string_format(hdr_tree,
1204 hf_header_array[hf_index], tvb,
1205 offset, next_offset - offset,
1207 tvb_format_text(tvb, offset, linelen));
1208 sip_element_tree = proto_item_add_subtree( sip_element_item,
1211 /* See if we have a SIP/SIPS uri enclosed in <>, if so anything in front is
1214 parameter_offset = tvb_find_guint8(tvb, value_offset,value_len, '<');
1215 if ( parameter_offset != -1){
1216 len = parameter_offset - value_offset;
1218 /* Something in front, must be display info
1219 * TODO: Get rid of trailing space(s)
1221 proto_tree_add_item(sip_element_tree, hf_sip_display, tvb, value_offset,
1224 parameter_offset ++;
1225 parameter_end_offset = parameter_offset;
1226 /* RFC3261 paragraph 20
1227 * The Contact, From, and To header fields contain a URI. If the URI
1228 * contains a comma, question mark or semicolon, the URI MUST be
1229 * enclosed in angle brackets (< and >). Any URI parameters are
1230 * contained within these brackets. If the URI is not enclosed in angle
1231 * brackets, any semicolon-delimited parameters are header-parameters,
1232 * not URI parameters.
1234 while (parameter_end_offset < line_end_offset){
1235 parameter_end_offset++;
1236 c = tvb_get_guint8(tvb, parameter_end_offset);
1242 goto separator_found;
1248 parameter_len = parameter_end_offset - parameter_offset;
1249 proto_tree_add_item(sip_element_tree, hf_sip_to_addr, tvb, parameter_offset,
1250 parameter_len, FALSE);
1251 /*info for the tap for voip_calls.c*/
1252 stat_info->tap_to_addr=tvb_get_string(tvb, parameter_offset, parameter_len);
1254 parameter_offset = parameter_end_offset + 1;
1258 parameter_end_offset = tvb_find_guint8(tvb, parameter_offset,( line_end_offset - parameter_offset), ';');
1259 if ( parameter_end_offset == -1)
1260 parameter_end_offset = line_end_offset;
1262 offset = parameter_end_offset;
1266 /* Extract SIP/SIPS URI */
1267 parameter_offset = value_offset;
1268 while (parameter_offset < line_end_offset
1269 && (tvb_strneql(tvb, parameter_offset, "sip", 3) != 0))
1271 len = parameter_offset - value_offset;
1273 /* Something in front, must be display info
1274 * TODO: Get rid of trailing space(s)
1276 proto_tree_add_item(sip_element_tree, hf_sip_display, tvb, value_offset,
1279 parameter_end_offset = tvb_find_guint8(tvb, parameter_offset,
1280 (line_end_offset - parameter_offset), ';');
1281 if ( parameter_end_offset == -1)
1282 parameter_end_offset = line_end_offset;
1283 parameter_len = parameter_end_offset - parameter_offset;
1284 proto_tree_add_item(sip_element_tree, hf_sip_to_addr, tvb, parameter_offset,
1285 parameter_len, FALSE);
1286 /*info for the tap for voip_calls.c*/
1287 stat_info->tap_to_addr=tvb_get_string(tvb, parameter_offset, parameter_len);
1288 offset = parameter_end_offset;
1290 /* Find parameter tag if present.
1291 * TODO make this generic to find any interesting parameter
1292 * use the same method as for SIP headers ?
1295 parameter_offset = offset;
1296 while (parameter_offset < line_end_offset
1297 && (tvb_strneql(tvb, parameter_offset, "tag=", 4) != 0))
1299 if ( parameter_offset < line_end_offset ){ /* Tag found */
1300 parameter_offset = parameter_offset + 4;
1301 parameter_end_offset = tvb_find_guint8(tvb, parameter_offset,
1302 (line_end_offset - parameter_offset), ';');
1303 if ( parameter_end_offset == -1)
1304 parameter_end_offset = line_end_offset;
1305 parameter_len = parameter_end_offset - parameter_offset;
1306 proto_tree_add_item(sip_element_tree, hf_sip_tag, tvb, parameter_offset,
1307 parameter_len, FALSE);
1314 sip_element_item = proto_tree_add_string_format(hdr_tree,
1315 hf_header_array[hf_index], tvb,
1316 offset, next_offset - offset,
1318 tvb_format_text(tvb, offset, linelen));
1319 sip_element_tree = proto_item_add_subtree( sip_element_item, ett_sip_element);
1321 /* See if we have a SIP/SIPS uri enclosed in <>, if so anything in front is
1324 parameter_offset = tvb_find_guint8(tvb, value_offset,value_len, '<');
1325 if ( parameter_offset != -1){
1326 len = parameter_offset - value_offset;
1328 /* Something in front, must be display info
1329 * TODO: Get rid of trailing space(s)
1331 proto_tree_add_item(sip_element_tree, hf_sip_display, tvb, value_offset,
1334 parameter_offset ++;
1335 parameter_end_offset = parameter_offset;
1336 /* RFC3261 paragraph 20
1337 * The Contact, From, and To header fields contain a URI. If the URI
1338 * contains a comma, question mark or semicolon, the URI MUST be
1339 * enclosed in angle brackets (< and >). Any URI parameters are
1340 * contained within these brackets. If the URI is not enclosed in angle
1341 * brackets, any semicolon-delimited parameters are header-parameters,
1342 * not URI parameters.
1344 while (parameter_end_offset < line_end_offset){
1345 parameter_end_offset++;
1346 c = tvb_get_guint8(tvb, parameter_end_offset);
1352 goto separator_found2;
1358 parameter_len = parameter_end_offset - parameter_offset;
1359 dfilter_store_sip_from_addr(tvb, sip_element_tree,
1360 parameter_offset, parameter_len);
1361 /*info for the tap for voip_calls.c*/
1362 stat_info->tap_from_addr=tvb_get_string(tvb, parameter_offset, parameter_len);
1363 parameter_offset = parameter_end_offset + 1;
1367 parameter_end_offset = tvb_find_guint8(tvb, parameter_offset,( line_end_offset - parameter_offset), ';');
1368 if ( parameter_end_offset == -1)
1369 parameter_end_offset = line_end_offset;
1371 offset = parameter_end_offset;
1375 /* Extract SIP/SIPS URI */
1376 parameter_offset = value_offset;
1377 while (parameter_offset < line_end_offset
1378 && (tvb_strneql(tvb, parameter_offset, "sip", 3) != 0))
1380 len = parameter_offset - value_offset;
1382 /* Something in front, must be display info
1383 * TODO: Get rid of trailing space(s)
1385 proto_tree_add_item(sip_element_tree, hf_sip_display, tvb, value_offset,
1388 parameter_end_offset = tvb_find_guint8(tvb, parameter_offset,
1389 (line_end_offset - parameter_offset), ';');
1390 if ( parameter_end_offset == -1)
1391 parameter_end_offset = line_end_offset;
1392 parameter_len = parameter_end_offset - parameter_offset;
1393 proto_tree_add_item(sip_element_tree, hf_sip_from_addr, tvb, parameter_offset,
1394 parameter_len, FALSE);
1395 /*info for the tap for voip_calls.c*/
1396 stat_info->tap_from_addr=tvb_get_string(tvb, parameter_offset, parameter_len);
1397 offset = parameter_end_offset;
1399 /* Find parameter tag if present.
1400 * TODO make this generic to find any interesting parameter
1401 * use the same method as for SIP headers ?
1404 parameter_offset = offset;
1405 while (parameter_offset < line_end_offset
1406 && (tvb_strneql(tvb, parameter_offset, "tag=", 4) != 0))
1408 if ( parameter_offset < line_end_offset ){ /* Tag found */
1409 parameter_offset = parameter_offset + 4;
1410 parameter_end_offset = tvb_find_guint8(tvb, parameter_offset,
1411 (line_end_offset - parameter_offset), ';');
1412 if ( parameter_end_offset == -1)
1413 parameter_end_offset = line_end_offset;
1414 parameter_len = parameter_end_offset - parameter_offset;
1415 proto_tree_add_item(sip_element_tree, hf_sip_tag, tvb, parameter_offset,
1416 parameter_len, FALSE);
1422 /* Store the sequence number */
1423 cseq_number = atoi(value);
1424 cseq_number_set = 1;
1425 stat_info->tap_cseq_number=cseq_number;
1427 /* Walk past number and spaces characters to get to start
1429 for (value_offset=0; value_offset < (gint)strlen(value); value_offset++)
1431 if (isalpha((guchar)value[value_offset]))
1436 if (value_offset == (gint)strlen(value))
1438 THROW(ReportedBoundsError);
1442 /* Extract method name from value */
1443 strlen_to_copy = strlen(value)-value_offset+1;
1444 if (strlen_to_copy > MAX_CSEQ_METHOD_SIZE) {
1445 /* Note the error in the protocol tree */
1447 proto_tree_add_string_format(hdr_tree,
1448 hf_header_array[hf_index], tvb,
1449 offset, next_offset - offset,
1450 value+value_offset, "%s String too big: %d bytes",
1451 sip_headers[POS_CSEQ].name,
1454 THROW(ReportedBoundsError);
1458 strncpy(cseq_method, value+value_offset, MIN(strlen_to_copy, MAX_CSEQ_METHOD_SIZE));
1460 /* Add 'CSeq' string item to tree */
1462 proto_tree_add_string_format(hdr_tree,
1463 hf_header_array[hf_index], tvb,
1464 offset, next_offset - offset,
1466 tvb_format_text(tvb, offset, linelen));
1472 /* Store the Call-id */
1473 strncpy(call_id, value,
1474 strlen(value)+1 < MAX_CALL_ID_SIZE ?
1477 stat_info->tap_call_id = g_strdup(call_id);
1479 /* Add 'Call-id' string item to tree */
1481 proto_tree_add_string_format(hdr_tree,
1482 hf_header_array[hf_index], tvb,
1483 offset, next_offset - offset,
1485 tvb_format_text(tvb, offset, linelen));
1490 if (strcmp(value, "0") == 0)
1494 /* Add 'Expires' string item to tree */
1496 proto_tree_add_string_format(hdr_tree,
1497 hf_header_array[hf_index], tvb,
1498 offset, next_offset - offset,
1500 tvb_format_text(tvb, offset, linelen));
1505 * Content-Type is the same as Internet
1506 * media type used by other dissectors,
1507 * appropriate dissector found by
1508 * lookup in "media_type" dissector table.
1510 case POS_CONTENT_TYPE :
1512 proto_tree_add_string_format(hdr_tree,
1513 hf_header_array[hf_index], tvb,
1514 offset, next_offset - offset,
1516 tvb_format_text(tvb, offset, linelen));
1518 content_type_len = value_len;
1519 semi_colon_offset = tvb_find_guint8(tvb, value_offset,linelen, ';');
1520 if ( semi_colon_offset != -1) {
1521 parameter_offset = semi_colon_offset +1;
1523 * Skip whitespace after the semicolon.
1525 while (parameter_offset < line_end_offset
1526 && ((c = tvb_get_guint8(tvb, parameter_offset)) == ' '
1529 content_type_len = semi_colon_offset - value_offset;
1530 content_type_parameter_str_len = line_end_offset - parameter_offset;
1531 content_type_parameter_str = tvb_get_string(tvb, parameter_offset,
1532 content_type_parameter_str_len);
1534 media_type_str = tvb_get_string(tvb, value_offset, content_type_len);
1535 #if GLIB_MAJOR_VERSION < 2
1536 media_type_str_lower_case = g_strdup(media_type_str);
1537 g_strdown(media_type_str_lower_case);
1539 media_type_str_lower_case = g_ascii_strdown(media_type_str, -1);
1541 g_free(media_type_str);
1546 sip_element_item = proto_tree_add_string_format(hdr_tree,
1547 hf_header_array[hf_index], tvb,
1548 offset, next_offset - offset,
1550 tvb_format_text(tvb, offset, linelen));
1551 sip_element_tree = proto_item_add_subtree( sip_element_item,
1554 if (strcmp(value, "*") == 0)
1556 contact_is_star = 1;
1560 comma_offset = value_offset;
1561 while((comma_offset = dissect_sip_contact_item(tvb, pinfo, sip_element_tree, comma_offset, next_offset)) != -1)
1564 if(comma_offset == next_offset)
1566 /* Line End reached: Stop Parsing */
1570 if(tvb_get_guint8(tvb, comma_offset) != ',')
1572 /* Undefined value reached: Stop Parsing */
1575 comma_offset++; /* skip comma */
1581 proto_tree_add_string_format(hdr_tree,
1582 hf_header_array[hf_index], tvb,
1583 offset, next_offset - offset,
1585 tvb_format_text(tvb, offset, linelen));
1591 }/* if colon_offset */
1592 offset = next_offset;
1595 if (tvb_offset_exists(tvb, next_offset)) {
1598 * There's a message body starting at "next_offset".
1599 * Set the length of the header item.
1601 proto_item_set_end(th, tvb, next_offset);
1602 next_tvb = tvb_new_subset(tvb, next_offset, -1, -1);
1604 ti = proto_tree_add_text(sip_tree, next_tvb, 0, -1,
1606 message_body_tree = proto_item_add_subtree(ti, ett_sip_message_body);
1609 /* give the content type parameters to sub dissectors */
1611 if ( media_type_str_lower_case != NULL ) {
1612 void *save_private_data = pinfo->private_data;
1613 pinfo->private_data = content_type_parameter_str;
1614 found_match = dissector_try_string(media_type_dissector_table,
1615 media_type_str_lower_case,
1618 g_free(media_type_str_lower_case);
1619 pinfo->private_data = save_private_data;
1620 /* If no match dump as text */
1622 g_free(content_type_parameter_str);
1623 if ( found_match != TRUE )
1626 while (tvb_offset_exists(next_tvb, offset)) {
1627 tvb_find_line_end(next_tvb, offset, -1, &next_offset, FALSE);
1628 linelen = next_offset - offset;
1629 if(message_body_tree) {
1630 proto_tree_add_text(message_body_tree, next_tvb, offset, linelen,
1631 "%s", tvb_format_text(next_tvb, offset, linelen));
1633 offset = next_offset;
1639 /* Add to info column interesting things learned from header fields. */
1640 if (check_col(pinfo->cinfo, COL_INFO))
1642 /* Registration requests */
1643 if (strcmp(sip_methods[current_method_idx], "REGISTER") == 0)
1645 if (contact_is_star && expires_is_0)
1647 col_append_str(pinfo->cinfo, COL_INFO, " (remove all bindings)");
1652 col_append_str(pinfo->cinfo, COL_INFO, " (fetch bindings)");
1656 /* Registration responses */
1657 if (line_type == STATUS_LINE && (strcmp(cseq_method, "REGISTER") == 0))
1659 col_append_fstr(pinfo->cinfo, COL_INFO, " (%d bindings)", contacts);
1663 /* Check if this packet is a resend. */
1664 resend_for_packet = sip_is_packet_resend(pinfo, cseq_method, call_id,
1665 cseq_number_set, cseq_number,
1667 /* Mark whether this is a resend for the tap */
1668 stat_info->resend = (resend_for_packet > 0);
1670 /* And add the filterable field to the request/response line */
1674 item = proto_tree_add_boolean(reqresp_tree, hf_sip_resend, tvb, 0, 0,
1675 resend_for_packet > 0);
1676 PROTO_ITEM_SET_GENERATED(item);
1677 if (resend_for_packet > 0)
1679 item = proto_tree_add_uint(reqresp_tree, hf_sip_original_frame,
1680 tvb, 0, 0, resend_for_packet);
1681 PROTO_ITEM_SET_GENERATED(item);
1686 if (global_sip_raw_text)
1687 tvb_raw_text_add(tvb, tree);
1689 /* Report this packet to the tap */
1690 if (!pinfo->in_error_pkt)
1692 tap_queue_packet(sip_tap, pinfo, stat_info);
1698 /* Display filter for SIP Request-Line */
1700 dfilter_sip_request_line(tvbuff_t *tvb, proto_tree *tree, guint meth_len)
1705 * We know we have the entire method; otherwise, "sip_parse_line()"
1706 * would have returned OTHER_LINE.
1708 string = tvb_get_string(tvb, 0, meth_len);
1710 proto_tree_add_string(tree, hf_Method, tvb, 0, meth_len, string);
1712 /* Copy request method for telling tap */
1713 stat_info->request_method = g_malloc(meth_len+1);
1714 strncpy(stat_info->request_method, string, meth_len+1);
1716 /* String no longer needed */
1720 /* Display filter for SIP Status-Line */
1722 dfilter_sip_status_line(tvbuff_t *tvb, proto_tree *tree)
1725 gint response_code = 0;
1728 * We know we have the entire status code; otherwise,
1729 * "sip_parse_line()" would have returned OTHER_LINE.
1730 * We also know that we have a version string followed by a
1731 * space at the beginning of the line, for the same reason.
1733 tvb_memcpy(tvb, (guint8 *)string, SIP2_HDR_LEN + 1, 3);
1735 response_code = atoi(string);
1737 /* Add numerical response code to tree */
1739 proto_tree_add_uint(tree, hf_Status_Code, tvb, SIP2_HDR_LEN + 1,
1743 /* Add response code for sending to tap */
1744 stat_info->response_code = response_code;
1747 void dfilter_store_sip_from_addr(tvbuff_t *tvb,proto_tree *tree,guint parameter_offset,
1748 guint parameter_len)
1750 proto_tree_add_item(tree, hf_sip_from_addr, tvb, parameter_offset,
1751 parameter_len, FALSE);
1754 /* From section 4.1 of RFC 2543:
1756 * Request-Line = Method SP Request-URI SP SIP-Version CRLF
1758 * From section 5.1 of RFC 2543:
1760 * Status-Line = SIP-version SP Status-Code SP Reason-Phrase CRLF
1762 * From section 7.1 of RFC 3261:
1764 * Unlike HTTP, SIP treats the version number as a literal string.
1765 * In practice, this should make no difference.
1768 sip_parse_line(tvbuff_t *tvb, gint linelen, guint *token_1_lenp)
1778 space_offset = tvb_find_guint8(tvb, 0, -1, ' ');
1779 if (space_offset <= 0) {
1781 * Either there's no space in the line (which means
1782 * the line is empty or doesn't have a token followed
1783 * by a space; neither is valid for a request or status), or
1784 * the first character in the line is a space (meaning
1785 * the method is empty, which isn't valid for a request,
1786 * or the SIP version is empty, which isn't valid for a
1791 token_1_len = space_offset;
1792 token_2_start = space_offset + 1;
1793 space_offset = tvb_find_guint8(tvb, token_2_start, -1, ' ');
1794 if (space_offset == -1) {
1796 * There's no space after the second token, so we don't
1797 * have a third token.
1801 token_2_len = space_offset - token_2_start;
1802 token_3_start = space_offset + 1;
1803 token_3_len = linelen - token_3_start;
1805 *token_1_lenp = token_1_len;
1808 * Is the first token a version string?
1810 if ( (strict_sip_version && (
1811 token_1_len == SIP2_HDR_LEN
1812 && tvb_strneql(tvb, 0, SIP2_HDR, SIP2_HDR_LEN) == 0)
1813 ) || (! strict_sip_version && (
1814 tvb_strneql(tvb, 0, "SIP/", 4) == 0)
1817 * Yes, so this is either a Status-Line or something
1818 * else other than a Request-Line. To be a Status-Line,
1819 * the second token must be a 3-digit number.
1821 if (token_2_len != 3) {
1823 * We don't have 3-character status code.
1827 if (!isdigit(tvb_get_guint8(tvb, token_2_start)) ||
1828 !isdigit(tvb_get_guint8(tvb, token_2_start + 1)) ||
1829 !isdigit(tvb_get_guint8(tvb, token_2_start + 2))) {
1831 * 3 characters yes, 3 digits no.
1838 * No, so this is either a Request-Line or something
1839 * other than a Status-Line. To be a Request-Line, the
1840 * second token must be a URI and the third token must
1841 * be a version string.
1843 if (token_2_len < 3) {
1845 * We don't have a URI consisting of at least 3
1850 colon_pos = tvb_find_guint8(tvb, token_2_start + 1, -1, ':');
1851 if (colon_pos == -1) {
1853 * There is no colon after the method, so the URI
1854 * doesn't have a colon in it, so it's not valid.
1858 if (colon_pos >= token_3_start) {
1860 * The colon is in the version string, not the URI.
1864 /* XXX - Check for a proper URI prefix? */
1865 if ( (strict_sip_version && (
1866 token_3_len != SIP2_HDR_LEN
1867 || tvb_strneql(tvb, token_3_start, SIP2_HDR, SIP2_HDR_LEN) == -1)
1868 ) || (! strict_sip_version && (
1869 tvb_strneql(tvb, token_3_start, "SIP/", 4) == -1)
1872 * The version string isn't an SIP version 2.0 version
1877 return REQUEST_LINE;
1881 static gboolean sip_is_known_request(tvbuff_t *tvb, int meth_offset,
1882 guint meth_len, guint *meth_idx)
1886 for (i = 1; i < array_length(sip_methods); i++) {
1887 if (meth_len == strlen(sip_methods[i]) &&
1888 tvb_strneql(tvb, meth_offset, sip_methods[i], meth_len) == 0)
1898 /* Returns index of method in sip_headers */
1899 static gint sip_is_known_sip_header(tvbuff_t *tvb, int offset, guint header_len)
1903 for (i = 1; i < array_length(sip_headers); i++) {
1904 if (header_len == strlen(sip_headers[i].name) &&
1905 tvb_strncaseeql(tvb, offset, sip_headers[i].name, header_len) == 0)
1907 if (sip_headers[i].compact_name != NULL &&
1908 header_len == strlen(sip_headers[i].compact_name) &&
1909 tvb_strncaseeql(tvb, offset, sip_headers[i].compact_name, header_len) == 0)
1917 * Display the entire message as raw text.
1920 tvb_raw_text_add(tvbuff_t *tvb, proto_tree *tree)
1922 proto_tree *raw_tree = NULL;
1923 proto_item *ti = NULL;
1924 int offset, next_offset, linelen;
1927 ti = proto_tree_add_item(tree, proto_raw_sip, tvb, 0, -1, FALSE);
1928 raw_tree = proto_item_add_subtree(ti, ett_raw_text);
1933 while (tvb_offset_exists(tvb, offset)) {
1934 tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE);
1935 linelen = next_offset - offset;
1937 proto_tree_add_text(raw_tree, tvb, offset, linelen,
1938 "%s", tvb_format_text(tvb, offset, linelen));
1940 offset = next_offset;
1944 /* Check to see if this packet is a resent request. Return value is number
1945 of the original frame this packet seems to be resending (0 = no resend). */
1946 guint sip_is_packet_resend(packet_info *pinfo,
1949 guchar cseq_number_set,
1950 guint32 cseq_number, line_type_t line_type)
1952 guint32 cseq_to_compare = 0;
1954 sip_hash_key *p_key = 0;
1955 sip_hash_value *p_val = 0;
1958 /* Only consider retransmission of UDP packets */
1959 if (pinfo->ptype != PT_UDP)
1964 /* Don't consider packets that appear to be resent only because
1965 they are e.g. returned in ICMP unreachable messages. */
1966 if (pinfo->in_error_pkt)
1971 /* A broken packet may have no cseq number set. Don't consider it as
1973 if (!cseq_number_set)
1978 /* Return any answer stored from previous dissection */
1979 if (pinfo->fd->flags.visited)
1981 return GPOINTER_TO_UINT(p_get_proto_data(pinfo->fd, proto_sip));
1984 /* No packet entry found, consult global hash table */
1986 /* Prepare the key */
1987 strncpy(key.call_id, call_id,
1988 (strlen(call_id)+1 <= MAX_CALL_ID_SIZE) ?
1991 COPY_ADDRESS(&key.dest_address, &pinfo->net_dst);
1992 COPY_ADDRESS(&key.source_address, &pinfo->net_src);
1993 key.dest_port = pinfo->destport;
1994 key.source_port = pinfo->srcport;
1997 p_val = (sip_hash_value*)g_hash_table_lookup(sip_hash, &key);
2001 /* Table entry found, we'll use its value for comparison */
2002 cseq_to_compare = p_val->cseq;
2006 /* Need to create a new table entry */
2008 /* Allocate a new key and value */
2009 p_key = g_mem_chunk_alloc(sip_hash_keys);
2010 p_val = g_mem_chunk_alloc(sip_hash_values);
2012 /* Just give up if allocations failed */
2013 if (!p_key || !p_val)
2018 /* Fill in key and value details */
2019 strcpy(p_key->call_id, call_id);
2020 COPY_ADDRESS(&(p_key->dest_address), &pinfo->net_dst);
2021 COPY_ADDRESS(&(p_key->source_address), &pinfo->net_src);
2022 p_key->dest_port = pinfo->destport;
2023 p_key->source_port = pinfo->srcport;
2025 p_val->cseq = cseq_number;
2026 p_val->transaction_state = nothing_seen;
2027 p_val->frame_number = 0;
2030 g_hash_table_insert(sip_hash, p_key, p_val);
2032 /* Assume have seen no cseq yet */
2033 cseq_to_compare = 0;
2037 /******************************************/
2038 /* Is it a resend??? */
2040 /* Does this look like a resent request (discount ACK, CANCEL) ? */
2041 if ((line_type == REQUEST_LINE) && (cseq_number == cseq_to_compare) &&
2042 (p_val->transaction_state == request_seen) &&
2043 (strcmp(cseq_method, "ACK") != 0) &&
2044 (strcmp(cseq_method, "CANCEL") != 0))
2046 result = p_val->frame_number;
2049 /* Does this look like a resent final response ? */
2050 if ((line_type == STATUS_LINE) && (cseq_number == cseq_to_compare) &&
2051 (p_val->transaction_state == final_response_seen) &&
2052 (stat_info->response_code >= 200) &&
2053 (stat_info->response_code == p_val->response_code))
2055 result = p_val->frame_number;
2058 /* Update state for this entry */
2059 p_val->cseq = cseq_number;
2064 p_val->transaction_state = request_seen;
2067 p_val->frame_number = pinfo->fd->num;
2071 if (stat_info->response_code >= 200)
2073 p_val->response_code = stat_info->response_code;
2074 p_val->transaction_state = final_response_seen;
2077 p_val->frame_number = pinfo->fd->num;
2082 p_val->transaction_state = provisional_response_seen;
2089 /* Store return value with this packet */
2090 p_add_proto_data(pinfo->fd, proto_sip, GUINT_TO_POINTER(result));
2096 /* Register the protocol with Ethereal */
2097 void proto_register_sip(void)
2100 /* Setup list of header fields */
2101 static hf_register_info hf[] = {
2104 { "Message Header", "sip.msg_hdr",
2105 FT_NONE, 0, NULL, 0,
2106 "Message Header in SIP message", HFILL }
2109 { "Method", "sip.Method",
2110 FT_STRING, BASE_NONE,NULL,0x0,
2111 "SIP Method", HFILL }
2114 { "Request-Line", "sip.Request-Line",
2115 FT_STRING, BASE_NONE,NULL,0x0,
2116 "SIP Request-Line", HFILL }
2119 { "Status-Code", "sip.Status-Code",
2120 FT_UINT32, BASE_DEC,NULL,0x0,
2121 "SIP Status Code", HFILL }
2124 { "Status-Line", "sip.Status-Line",
2125 FT_STRING, BASE_NONE,NULL,0x0,
2126 "SIP Status-Line", HFILL }
2129 { "SIP Display info", "sip.display.info",
2130 FT_STRING, BASE_NONE,NULL,0x0,
2131 "RFC 3261: Display info", HFILL }
2134 { "SIP to address", "sip.to.addr",
2135 FT_STRING, BASE_NONE,NULL,0x0,
2136 "RFC 3261: to addr", HFILL }
2138 { &hf_sip_from_addr,
2139 { "SIP from address", "sip.from.addr",
2140 FT_STRING, BASE_NONE,NULL,0x0,
2141 "RFC 3261: from addr", HFILL }
2143 { &hf_sip_contact_addr,
2144 { "SIP contact address", "sip.contact.addr",
2145 FT_STRING, BASE_NONE,NULL,0x0,
2146 "RFC 3261: contact addr", HFILL }
2150 FT_STRING, BASE_NONE,NULL,0x0,
2151 "RFC 3261: SIP Uri", HFILL }
2153 { &hf_sip_contact_item,
2154 { "Contact Binding", "sip.contact.binding",
2155 FT_STRING, BASE_NONE,NULL,0x0,
2156 "RFC 3261: one contact binding", HFILL }
2159 { "SIP tag", "sip.tag",
2160 FT_STRING, BASE_NONE,NULL,0x0,
2161 "RFC 3261: tag", HFILL }
2163 { &hf_header_array[POS_ACCEPT],
2164 { "Accept", "sip.Accept",
2165 FT_STRING, BASE_NONE,NULL,0x0,
2166 "RFC 3261: Accept Header", HFILL }
2168 { &hf_header_array[POS_ACCEPT_CONTACT],
2169 { "Accept-Contact", "sip.Accept-Contact",
2170 FT_STRING, BASE_NONE,NULL,0x0,
2171 "RFC 3841: Accept-Contact Header", HFILL }
2173 { &hf_header_array[POS_ACCEPT_ENCODING],
2174 { "Accept-Encoding", "sip.Accept-Encoding",
2175 FT_STRING, BASE_NONE,NULL,0x0,
2176 "RFC 3841: Accept-Encoding Header", HFILL }
2178 { &hf_header_array[POS_ACCEPT_LANGUAGE],
2179 { "Accept-Language", "sip.Accept-Language",
2180 FT_STRING, BASE_NONE,NULL,0x0,
2181 "RFC 3261: Accept-Language Header", HFILL }
2183 { &hf_header_array[POS_ACCEPT_RESOURCE_PRIORITY],
2184 { "Accept-Resource-Priority", "sip.Accept-Resource-Priority",
2185 FT_STRING, BASE_NONE,NULL,0x0,
2186 "Draft: Accept-Resource-Priority Header", HFILL }
2188 { &hf_header_array[POS_ALERT_INFO],
2189 { "Alert-Info", "sip.Alert-Info",
2190 FT_STRING, BASE_NONE,NULL,0x0,
2191 "RFC 3261: Alert-Info Header", HFILL }
2193 { &hf_header_array[POS_ALLOW],
2194 { "Allow", "sip.Allow",
2195 FT_STRING, BASE_NONE,NULL,0x0,
2196 "RFC 3261: Allow Header", HFILL }
2198 { &hf_header_array[POS_ALLOW_EVENTS],
2199 { "Allow-Events", "sip.Allow-Events",
2200 FT_STRING, BASE_NONE,NULL,0x0,
2201 "RFC 3265: Allow-Events Header", HFILL }
2203 { &hf_header_array[POS_AUTHENTICATION_INFO],
2204 { "Authentication-Info", "sip.Authentication-Info",
2205 FT_STRING, BASE_NONE,NULL,0x0,
2206 "RFC 3261: Authentication-Info Header", HFILL }
2208 { &hf_header_array[POS_AUTHORIZATION],
2209 { "Authorization", "sip.Authorization",
2210 FT_STRING, BASE_NONE,NULL,0x0,
2211 "RFC 3261: Authorization Header", HFILL }
2213 { &hf_header_array[POS_CALL_ID],
2214 { "Call-ID", "sip.Call-ID",
2215 FT_STRING, BASE_NONE,NULL,0x0,
2216 "RFC 3261: Call-ID Header", HFILL }
2218 { &hf_header_array[POS_CALL_INFO],
2219 { "Call-Info", "sip.Call-Info",
2220 FT_STRING, BASE_NONE,NULL,0x0,
2221 "RFC 3261: Call-Info Header", HFILL }
2223 { &hf_header_array[POS_CONTACT],
2224 { "Contact", "sip.Contact",
2225 FT_STRING, BASE_NONE,NULL,0x0,
2226 "RFC 3261: Contact Header", HFILL }
2228 { &hf_header_array[POS_CONTENT_DISPOSITION],
2229 { "Content-Disposition", "sip.Content-Disposition",
2230 FT_STRING, BASE_NONE,NULL,0x0,
2231 "RFC 3261: Content-Disposition Header", HFILL }
2233 { &hf_header_array[POS_CONTENT_ENCODING],
2234 { "Content-Encoding", "sip.Content-Encoding",
2235 FT_STRING, BASE_NONE,NULL,0x0,
2236 "RFC 3261: Content-Encoding Header", HFILL }
2238 { &hf_header_array[POS_CONTENT_LANGUAGE],
2239 { "Content-Language", "sip.Content-Language",
2240 FT_STRING, BASE_NONE,NULL,0x0,
2241 "RFC 3261: Content-Language Header", HFILL }
2243 { &hf_header_array[POS_CONTENT_LENGTH],
2244 { "Content-Length", "sip.Content-Length",
2245 FT_STRING, BASE_NONE,NULL,0x0,
2246 "RFC 3261: Content-Length Header", HFILL }
2248 { &hf_header_array[POS_CONTENT_TYPE],
2249 { "Content-Type", "sip.Content-Type",
2250 FT_STRING, BASE_NONE,NULL,0x0,
2251 "RFC 3261: Content-Type Header", HFILL }
2253 { &hf_header_array[POS_CSEQ],
2254 { "CSeq", "sip.CSeq",
2255 FT_STRING, BASE_NONE,NULL,0x0,
2256 "RFC 3261: CSeq Header", HFILL }
2258 { &hf_header_array[POS_DATE],
2259 { "Date", "sip.Date",
2260 FT_STRING, BASE_NONE,NULL,0x0,
2261 "RFC 3261: Date Header", HFILL }
2263 { &hf_header_array[POS_ERROR_INFO],
2264 { "Error-Info", "sip.Error-Info",
2265 FT_STRING, BASE_NONE,NULL,0x0,
2266 "RFC 3261: Error-Info Header", HFILL }
2268 { &hf_header_array[POS_EVENT],
2269 { "Event", "sip.Event",
2270 FT_STRING, BASE_NONE,NULL,0x0,
2271 "RFC 3265: Event Header", HFILL }
2273 { &hf_header_array[POS_EXPIRES],
2274 { "Expires", "sip.Expires",
2275 FT_STRING, BASE_NONE,NULL,0x0,
2276 "RFC 3261: Expires Header", HFILL }
2278 { &hf_header_array[POS_FROM],
2279 { "From", "sip.From",
2280 FT_STRING, BASE_NONE,NULL,0x0,
2281 "RFC 3261: From Header", HFILL }
2283 { &hf_header_array[POS_IN_REPLY_TO],
2284 { "In-Reply-To", "sip.In-Reply-To",
2285 FT_STRING, BASE_NONE,NULL,0x0,
2286 "RFC 3261: In-Reply-To Header", HFILL }
2288 { &hf_header_array[POS_JOIN],
2289 { "Join", "sip.Join",
2290 FT_STRING, BASE_NONE,NULL,0x0,
2291 "Draft: Join Header", HFILL }
2293 { &hf_header_array[POS_MAX_FORWARDS],
2294 { "Max-Forwards", "sip.Max-Forwards",
2295 FT_STRING, BASE_NONE,NULL,0x0,
2296 "RFC 3261: Max-Forwards Header", HFILL }
2298 { &hf_header_array[POS_MIME_VERSION],
2299 { "MIME-Version", "sip.MIME-Version",
2300 FT_STRING, BASE_NONE,NULL,0x0,
2301 "RFC 3261: MIME-Version Header", HFILL }
2303 { &hf_header_array[POS_MIN_EXPIRES],
2304 { "Min-Expires", "sip.Min-Expires",
2305 FT_STRING, BASE_NONE,NULL,0x0,
2306 "RFC 3261: Min-Expires Header", HFILL }
2308 { &hf_header_array[POS_MIN_SE],
2309 { "Min-SE", "sip.Min-SE",
2310 FT_STRING, BASE_NONE,NULL,0x0,
2311 "Draft: Min-SE Header", HFILL }
2313 { &hf_header_array[POS_ORGANIZATION],
2314 { "Organization", "sip.Organization",
2315 FT_STRING, BASE_NONE,NULL,0x0,
2316 "RFC 3261: Organization Header", HFILL }
2318 { &hf_header_array[POS_P_ACCESS_NETWORK_INFO],
2319 { "P-Access-Network-Info", "sip.P-Access-Network-Info",
2320 FT_STRING, BASE_NONE,NULL,0x0,
2321 "P-Access-Network-Info Header", HFILL }
2324 { &hf_header_array[POS_P_ASSERTED_IDENTITY],
2325 { "P-Asserted-Identity", "sip.P-Asserted-Identity",
2326 FT_STRING, BASE_NONE,NULL,0x0,
2327 "P-Asserted-Identity Header", HFILL }
2330 { &hf_header_array[POS_P_ASSOCIATED_URI],
2331 { "P-Associated-URI", "sip.P-Associated-URI",
2332 FT_STRING, BASE_NONE,NULL,0x0,
2333 "P-Associated-URI Header", HFILL }
2336 { &hf_header_array[POS_P_CALLED_PARTY_ID],
2337 { "P-Called-Party-ID", "sip.P-Called-Party-ID",
2338 FT_STRING, BASE_NONE,NULL,0x0,
2339 "P-Called-Party-ID Header", HFILL }
2342 { &hf_header_array[POS_P_CHARGING_FUNCTION_ADDRESSES],
2343 { "P-Charging-Function-Addresses","sip.P-Charging-Function-Addresses",
2344 FT_STRING, BASE_NONE,NULL,0x0,
2345 "P-Charging-Function-Addresses", HFILL }
2348 { &hf_header_array[POS_P_CHARGING_VECTOR],
2349 { "P-Charging-Vector", "sip.P-Charging-Vector",
2350 FT_STRING, BASE_NONE,NULL,0x0,
2351 "P-Charging-Vector Header", HFILL }
2354 { &hf_header_array[POS_P_DCS_TRACE_PARTY_ID],
2355 { "P-DCS-Trace-Party-ID", "sip.P-DCS-Trace-Party-ID",
2356 FT_STRING, BASE_NONE,NULL,0x0,
2357 "P-DCS-Trace-Party-ID Header", HFILL }
2360 { &hf_header_array[POS_P_DCS_OSPS],
2361 { "P-DCS-OSPS", "sip.P-DCS-OSPS",
2362 FT_STRING, BASE_NONE,NULL,0x0,
2363 "P-DCS-OSPS Header", HFILL }
2366 { &hf_header_array[POS_P_DCS_BILLING_INFO],
2367 { "P-DCS-Billing-Info", "sip.P-DCS-Billing-Info",
2368 FT_STRING, BASE_NONE,NULL,0x0,
2369 "P-DCS-Billing-Info Header", HFILL }
2372 { &hf_header_array[POS_P_DCS_LAES],
2373 { "P-DCS-LAES", "sip.P-DCS-LAES",
2374 FT_STRING, BASE_NONE,NULL,0x0,
2375 "P-DCS-LAES Header", HFILL }
2378 { &hf_header_array[POS_P_DCS_REDIRECT],
2379 { "P-DCS-Redirect", "sip.P-DCS-Redirect",
2380 FT_STRING, BASE_NONE,NULL,0x0,
2381 "P-DCS-Redirect Header", HFILL }
2384 { &hf_header_array[POS_P_MEDIA_AUTHORIZATION],
2385 { "P-Media-Authorization", "sip.P-Media-Authorization",
2386 FT_STRING, BASE_NONE,NULL,0x0,
2387 "P-Media-Authorization Header", HFILL }
2390 { &hf_header_array[POS_P_PREFERRED_IDENTITY],
2391 { "P-Preferred-Identity", "sip.P-Preferred-Identity",
2392 FT_STRING, BASE_NONE,NULL,0x0,
2393 "P-Preferred-Identity Header", HFILL }
2396 { &hf_header_array[POS_P_VISITED_NETWORK_ID],
2397 { "P-Visited-Network-ID", "sip.P-Visited-Network-ID",
2398 FT_STRING, BASE_NONE,NULL,0x0,
2399 "P-Visited-Network-ID Header", HFILL }
2402 { &hf_header_array[POS_PATH],
2403 { "Path", "sip.Path",
2404 FT_STRING, BASE_NONE,NULL,0x0,
2405 "Path Header", HFILL }
2408 { &hf_header_array[POS_PRIORITY],
2409 { "Priority", "sip.Priority",
2410 FT_STRING, BASE_NONE,NULL,0x0,
2411 "RFC 3261: Priority Header", HFILL }
2413 { &hf_header_array[POS_PRIVACY],
2414 { "Privacy", "sip.Privacy",
2415 FT_STRING, BASE_NONE,NULL,0x0,
2416 "Privacy Header", HFILL }
2419 { &hf_header_array[POS_PROXY_AUTHENTICATE],
2420 { "Proxy-Authenticate", "sip.Proxy-Authenticate",
2421 FT_STRING, BASE_NONE,NULL,0x0,
2422 "RFC 3261: Proxy-Authenticate Header", HFILL }
2424 { &hf_header_array[POS_PROXY_AUTHORIZATION],
2425 { "Proxy-Authorization", "sip.Proxy-Authorization",
2426 FT_STRING, BASE_NONE,NULL,0x0,
2427 "RFC 3261: Proxy-Authorization Header", HFILL }
2430 { &hf_header_array[POS_PROXY_REQUIRE],
2431 { "Proxy-Require", "sip.Proxy-Require",
2432 FT_STRING, BASE_NONE,NULL,0x0,
2433 "RFC 3261: Proxy-Require Header", HFILL }
2435 { &hf_header_array[POS_RACK],
2436 { "RAck", "sip.RAck",
2437 FT_STRING, BASE_NONE,NULL,0x0,
2438 "RFC 3262: RAck Header", HFILL }
2440 { &hf_header_array[POS_REASON],
2441 { "Reason", "sip.Reason",
2442 FT_STRING, BASE_NONE,NULL,0x0,
2443 "RFC 3326 Reason Header", HFILL }
2445 { &hf_header_array[POS_RECORD_ROUTE],
2446 { "Record-Route", "sip.Record-Route",
2447 FT_STRING, BASE_NONE,NULL,0x0,
2448 "RFC 3261: Record-Route Header", HFILL }
2450 { &hf_header_array[POS_REFERED_BY],
2451 { "Refered By", "sip.Refered-by",
2452 FT_STRING, BASE_NONE,NULL,0x0,
2453 "RFC 3892: Refered-by Header", HFILL }
2455 { &hf_header_array[POS_REJECT_CONTACT],
2456 { "Reject-Contact", "sip.Reject-Contact",
2457 FT_STRING, BASE_NONE,NULL,0x0,
2458 "RFC 3841: Reject-Contact Header", HFILL }
2460 { &hf_header_array[POS_REPLACES],
2461 { "Replaces", "sip.Replaces",
2462 FT_STRING, BASE_NONE,NULL,0x0,
2463 "RFC 3891: Replaces Header", HFILL }
2465 { &hf_header_array[POS_REPLY_TO],
2466 { "Reply-To", "sip.Reply-To",
2467 FT_STRING, BASE_NONE,NULL,0x0,
2468 "RFC 3261: Reply-To Header", HFILL }
2470 { &hf_header_array[POS_REQUEST_DISPOSITION],
2471 { "Request-Disposition", "sip.Request-Disposition",
2472 FT_STRING, BASE_NONE,NULL,0x0,
2473 "RFC 3841: Request-Disposition Header", HFILL }
2475 { &hf_header_array[POS_REQUIRE],
2476 { "Require", "sip.Require",
2477 FT_STRING, BASE_NONE,NULL,0x0,
2478 "RFC 3261: Require Header", HFILL }
2480 { &hf_header_array[POS_RESOURCE_PRIORITY],
2481 { "Resource-Priority", "sip.Resource-Priority",
2482 FT_STRING, BASE_NONE,NULL,0x0,
2483 "Draft: Resource-Priority Header", HFILL }
2485 { &hf_header_array[POS_RETRY_AFTER],
2486 { "Retry-After", "sip.Retry-After",
2487 FT_STRING, BASE_NONE,NULL,0x0,
2488 "RFC 3261: Retry-After Header", HFILL }
2490 { &hf_header_array[POS_ROUTE],
2491 { "Route", "sip.Route",
2492 FT_STRING, BASE_NONE,NULL,0x0,
2493 "RFC 3261: Route Header", HFILL }
2495 { &hf_header_array[POS_RSEQ],
2496 { "RSeq", "sip.RSeq",
2497 FT_STRING, BASE_NONE,NULL,0x0,
2498 "RFC 3262: RSeq Header", HFILL }
2500 { &hf_header_array[ POS_SECURITY_CLIENT],
2501 { "Security-Client", "sip.Security-Client",
2502 FT_STRING, BASE_NONE,NULL,0x0,
2503 "RFC 3329 Security-Client Header", HFILL }
2505 { &hf_header_array[ POS_SECURITY_SERVER],
2506 { "Security-Server", "sip.Security-Server",
2507 FT_STRING, BASE_NONE,NULL,0x0,
2508 "RFC 3329 Security-Server Header", HFILL }
2510 { &hf_header_array[ POS_SECURITY_VERIFY],
2511 { "Security-Verify", "sip.Security-Verify",
2512 FT_STRING, BASE_NONE,NULL,0x0,
2513 "RFC 3329 Security-Verify Header", HFILL }
2515 { &hf_header_array[POS_SERVER],
2516 { "Server", "sip.Server",
2517 FT_STRING, BASE_NONE,NULL,0x0,
2518 "RFC 3261: Server Header", HFILL }
2520 { &hf_header_array[POS_SERVICE_ROUTE],
2521 { "Service-Route", "sip.Service-Route",
2522 FT_STRING, BASE_NONE,NULL,0x0,
2523 "Service-Route Header", HFILL }
2525 { &hf_header_array[POS_SESSION_EXPIRES],
2526 { "Session-Expires", "sip.Session-Expires",
2527 FT_STRING, BASE_NONE,NULL,0x0,
2528 "Session-Expires Header", HFILL }
2530 { &hf_header_array[POS_SIP_ETAG],
2531 { "ETag", "sip.ETag",
2532 FT_STRING, BASE_NONE,NULL,0x0,
2533 "SIP-ETag Header", HFILL }
2535 { &hf_header_array[POS_SIP_IF_MATCH],
2536 { "If_Match", "sip.If_Match",
2537 FT_STRING, BASE_NONE,NULL,0x0,
2538 "SIP-If-Match Header", HFILL }
2540 { &hf_header_array[POS_SUBJECT],
2541 { "Subject", "sip.Subject",
2542 FT_STRING, BASE_NONE,NULL,0x0,
2543 "RFC 3261: Subject Header", HFILL }
2545 { &hf_header_array[POS_SUBSCRIPTION_STATE],
2546 { "Subscription-State", "sip.Subscription-State",
2547 FT_STRING, BASE_NONE,NULL,0x0,
2548 "RFC 3265: Subscription-State Header", HFILL }
2550 { &hf_header_array[POS_SUPPORTED],
2551 { "Supported", "sip.Supported",
2552 FT_STRING, BASE_NONE,NULL,0x0,
2553 "RFC 3261: Supported Header", HFILL }
2555 { &hf_header_array[POS_TIMESTAMP],
2556 { "Timestamp", "sip.Timestamp",
2557 FT_STRING, BASE_NONE,NULL,0x0,
2558 "RFC 3261: Timestamp Header", HFILL }
2560 { &hf_header_array[POS_TO],
2562 FT_STRING, BASE_NONE,NULL,0x0,
2563 "RFC 3261: To Header", HFILL }
2566 { &hf_header_array[POS_UNSUPPORTED],
2567 { "Unsupported", "sip.Unsupported",
2568 FT_STRING, BASE_NONE,NULL,0x0,
2569 "RFC 3261: Unsupported Header", HFILL }
2571 { &hf_header_array[POS_USER_AGENT],
2572 { "User-Agent", "sip.User-Agent",
2573 FT_STRING, BASE_NONE,NULL,0x0,
2574 "RFC 3261: User-Agent Header", HFILL }
2576 { &hf_header_array[POS_VIA],
2578 FT_STRING, BASE_NONE,NULL,0x0,
2579 "RFC 3261: Via Header", HFILL }
2581 { &hf_header_array[POS_WARNING],
2582 { "Warning", "sip.Warning",
2583 FT_STRING, BASE_NONE,NULL,0x0,
2584 "RFC 3261: Warning Header", HFILL }
2587 { &hf_header_array[POS_WWW_AUTHENTICATE],
2588 { "WWW-Authenticate", "sip.WWW-Authenticate",
2589 FT_STRING, BASE_NONE,NULL,0x0,
2590 "RFC 3261: WWW-Authenticate Header", HFILL }
2592 { &hf_header_array[POS_REFER_TO],
2593 { "Refer-To", "sip.Refer-To",
2594 FT_STRING, BASE_NONE,NULL,0x0,
2595 "Refer-To Header", HFILL }
2598 { "Resent Packet", "sip.resend",
2599 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2602 { &hf_sip_original_frame,
2603 { "Suspected resend of frame", "sip.resend-original",
2604 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2605 "Original transmission of frame", HFILL}}
2608 /* Setup protocol subtree array */
2609 static gint *ett[] = {
2615 &ett_sip_contact_item,
2616 &ett_sip_message_body,
2618 static gint *ett_raw[] = {
2622 module_t *sip_module;
2624 /* Register the protocol name and description */
2625 proto_sip = proto_register_protocol("Session Initiation Protocol",
2627 proto_raw_sip = proto_register_protocol("Session Initiation Protocol (SIP as raw text)",
2628 "Raw_SIP", "raw_sip");
2629 new_register_dissector("sip", dissect_sip, proto_sip);
2631 /* Required function calls to register the header fields and subtrees used */
2632 proto_register_field_array(proto_sip, hf, array_length(hf));
2633 proto_register_subtree_array(ett, array_length(ett));
2634 proto_register_subtree_array(ett_raw, array_length(ett_raw));
2636 /* SIP content type and internet media type used by other dissectors are the same */
2637 media_type_dissector_table = find_dissector_table("media_type");
2639 sip_module = prefs_register_protocol(proto_sip, NULL);
2641 prefs_register_bool_preference(sip_module, "display_raw_text",
2642 "Display raw text for SIP message",
2643 "Specifies that the raw text of the "
2644 "SIP message should be displayed "
2645 "in addition to the dissection tree",
2646 &global_sip_raw_text);
2647 prefs_register_bool_preference(sip_module, "strict_sip_version",
2648 "Enforce strict SIP version check (" SIP2_HDR ")",
2649 "If enabled, only " SIP2_HDR " traffic will be dissected as SIP. "
2650 "Disable it to allow SIP traffic with a different version "
2651 "to be dissected as SIP.",
2652 &strict_sip_version);
2654 register_init_routine(&sip_init_protocol);
2656 /* Register for tapping */
2657 sip_tap = register_tap("sip");
2661 proto_reg_handoff_sip(void)
2663 dissector_handle_t sip_handle, sip_tcp_handle;
2665 sip_handle = new_create_dissector_handle(dissect_sip, proto_sip);
2666 dissector_add("udp.port", UDP_PORT_SIP, sip_handle);
2667 dissector_add_string("media_type", "message/sip", sip_handle);
2668 sigcomp_handle = find_dissector("sigcomp");
2670 sip_tcp_handle = create_dissector_handle(dissect_sip_tcp, proto_sip);
2671 dissector_add("tcp.port", TCP_PORT_SIP, sip_tcp_handle);
2673 heur_dissector_add("udp", dissect_sip_heur, proto_sip);
2674 heur_dissector_add("tcp", dissect_sip_heur, proto_sip);
2675 heur_dissector_add("sctp", dissect_sip_heur, proto_sip);