aboutsummaryrefslogtreecommitdiffstats
path: root/packet-sip.c
blob: 6c13520fbebdcc6a72b2b000664c04db016ff709 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
/* packet-sip.c
 * Routines for the Session Initiation Protocol (SIP) dissection.
 * RFC 2543
 * 
 * TODO: Pay attention to Content-Type: It might not always be SDP.
 *       Add hf_* fields for filtering support.
 *       Add sip msg body dissection based on Content-Type for:
 *                SDP, MIME, and other types
 *       Align SIP methods with recent Internet Drafts or RFC
 *               (SIP INFO, rfc2976 - done)
 *               (SIP SUBSCRIBE-NOTIFY - done)
 *               (SIP REFER - done)
 *               check for other
 *
 * Copyright 2000, Heikki Vatiainen <hessu@cs.tut.fi>
 * Copyright 2001, Jean-Francois Mule <jfm@clarent.com>
 *
 * $Id: packet-sip.c,v 1.17 2001/10/26 18:28:16 gram Exp $
 *
 * Ethereal - Network traffic analyzer
 * By Gerald Combs <gerald@ethereal.com>
 * Copyright 1998 Gerald Combs
 *
 * Copied from packet-cops.c
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <glib.h>
#include "packet.h"

#define TCP_PORT_SIP 5060
#define UDP_PORT_SIP 5060

/* Initialize the protocol and registered fields */
static gint proto_sip = -1;
static gint hf_msg_hdr = -1;

/* Initialize the subtree pointers */
static gint ett_sip = -1;
static gint ett_sip_hdr = -1;

static const char *sip_methods[] = {
        "<Invalid method>",      /* Pad so that the real methods start at index 1 */
        "INVITE",
        "ACK",
        "OPTIONS",
        "BYE",
        "CANCEL",
        "REGISTER",
        "INFO",
        "REFER",
        "SUBSCRIBE",
        "NOTIFY"
};

static gboolean sip_is_request(tvbuff_t *tvb, guint32 offset);
static gint sip_get_msg_offset(tvbuff_t *tvb, guint32 offset);
 
static dissector_handle_t sdp_handle;

#define SIP2_HDR "SIP/2.0 "
#define SIP2_HDR_LEN (strlen (SIP2_HDR))

/* Code to actually dissect the packets */
static void dissect_sip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
        guint32 offset;
        gint eol, next_offset, msg_offset;
        tvbuff_t *next_tvb;
        gboolean is_request;

	/*
	 * Note that "tvb_strneql()" doesn't throw exceptions, so
	 * "sip_is_request()" won't throw an exception.
	 *
	 * Note that "tvb_find_line_end()" will return a value that
	 * is not longer than what's in the buffer, so the
	 * "tvb_get_ptr()" call s below won't throw exceptions.
	 */
        offset = 0;
        eol = tvb_find_line_end(tvb, 0, -1, &next_offset);
        is_request = sip_is_request(tvb, 0);
	/* XXX - Is this case-sensitive?  RFC 2543 didn't explicitly say. */
	if (tvb_strneql(tvb, 0, SIP2_HDR, SIP2_HDR_LEN) != 0 && ! is_request)
		goto bad;
	  
        if (check_col(pinfo->fd, COL_PROTOCOL)) 
                col_set_str(pinfo->fd, COL_PROTOCOL, "SIP");
    

        if (check_col(pinfo->fd, COL_INFO))
                col_add_fstr(pinfo->fd, COL_INFO, "%s: %s",
                             is_request ? "Request" : "Status",
                             is_request ? 
                             tvb_format_text(tvb, 0, eol - SIP2_HDR_LEN) :
                             tvb_format_text(tvb, SIP2_HDR_LEN, eol - SIP2_HDR_LEN));

        msg_offset = sip_get_msg_offset(tvb, offset);
        if (msg_offset < 0) goto bad;

        if (tree) {
                proto_item *ti, *th;
                proto_tree *sip_tree, *hdr_tree;

                ti = proto_tree_add_item(tree, proto_sip, tvb, 0, tvb_length(tvb), FALSE);
                sip_tree = proto_item_add_subtree(ti, ett_sip);

                proto_tree_add_text(sip_tree, tvb, 0, next_offset, "%s-Line: %s",
                                    is_request ? "Request" : "Status",
                                    tvb_format_text(tvb, 0, eol));

                offset = next_offset;
                th = proto_tree_add_item(sip_tree, hf_msg_hdr, tvb, offset, msg_offset - offset, FALSE);
                hdr_tree = proto_item_add_subtree(th, ett_sip_hdr);

                /* - 2 since we have a CRLF separating the message-body */
                while (msg_offset - 2 > (int) offset) {
                        eol = tvb_find_line_end(tvb, offset, -1, &next_offset);
                        proto_tree_add_text(hdr_tree, tvb, offset, next_offset - offset, "%s",
                                            tvb_format_text(tvb, offset, eol));
                        offset = next_offset;
                }
                offset += 2;  /* Skip the CRLF mentioned above */
       }

        if (tvb_length_remaining(tvb, msg_offset) > 0) {
                next_tvb = tvb_new_subset(tvb, offset, -1, -1);
                call_dissector(sdp_handle, next_tvb, pinfo, tree);
        }

        return;

  bad:
        next_tvb = tvb_new_subset(tvb, offset, -1, -1);
        dissect_data(next_tvb, 0, pinfo, tree);

        return;
}

/* Returns the offset to the start of the optional message-body, or
 * -1 for an error.
 */
static gint sip_get_msg_offset(tvbuff_t *tvb, guint32 offset)
{
        gint eol;

        while ((eol = tvb_find_guint8(tvb, offset, tvb_length_remaining(tvb, offset), '\r')) > 0) {
                        if (tvb_get_guint8(tvb, eol + 1) == '\n' && 
                            tvb_get_guint8(tvb, eol + 2) == '\r' && 
                            tvb_get_guint8(tvb, eol + 3) == '\n')
                                return eol + 4;
                        offset = eol + 2;
        }

        return -1;
}
                
static gboolean sip_is_request(tvbuff_t *tvb, guint32 offset)
{
        u_int i;

        for (i = 1; i < array_length(sip_methods); i++) {
                if (tvb_strneql(tvb, offset, sip_methods[i], strlen(sip_methods[i])) == 0)
                        return TRUE;
        }

        return FALSE;
}

/* Register the protocol with Ethereal */
void proto_register_sip(void)
{                 

        /* Setup list of header fields */
        static hf_register_info hf[] = {

                { &hf_msg_hdr,
                        { "Message Header",           "sip.msg_hdr",
                        FT_NONE, 0, NULL, 0,
                        "Message Header in SIP message", HFILL }
                },
        };

        /* Setup protocol subtree array */
        static gint *ett[] = {
                &ett_sip,
                &ett_sip_hdr,
        };

        /* Register the protocol name and description */
        proto_sip = proto_register_protocol("Session Initiation Protocol",
	    "SIP", "sip");

        /* Required function calls to register the header fields and subtrees used */
        proto_register_field_array(proto_sip, hf, array_length(hf));
        proto_register_subtree_array(ett, array_length(ett));
}

void
proto_reg_handoff_sip(void)
{
        dissector_add("tcp.port", TCP_PORT_SIP, dissect_sip, proto_sip);
        dissector_add("udp.port", UDP_PORT_SIP, dissect_sip, proto_sip);

	/*
	 * Get a handle for the SDP dissector.
	 */
	sdp_handle = find_dissector("sdp");
}