Instead of saying the "manuf" file is in "/usr/local/etc/manuf", say
[obnox/wireshark/wip.git] / packet-http.c
1 /* packet-http.c
2  * Routines for HTTP packet disassembly
3  *
4  * Guy Harris <guy@alum.mit.edu>
5  *
6  * $Id: packet-http.c,v 1.39 2001/09/04 01:01:46 guy Exp $
7  *
8  * Ethereal - Network traffic analyzer
9  * By Gerald Combs <gerald@zing.org>
10  * Copyright 1998 Gerald Combs
11  *
12  * 
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  * 
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  * 
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
26  *
27  *
28  */
29
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif
33
34 #ifdef HAVE_SYS_TYPES_H
35 #include <sys/types.h>
36 #endif
37
38 #include <string.h>
39 #include <ctype.h>
40
41 #include <glib.h>
42 #include "packet.h"
43 #include "strutil.h"
44
45 #include "packet-http.h"
46
47 typedef enum _http_type {
48         HTTP_REQUEST,
49         HTTP_RESPONSE,
50         HTTP_NOTIFICATION,
51         HTTP_OTHERS
52 } http_type_t;
53
54 static int proto_http = -1;
55 static int hf_http_notification = -1;
56 static int hf_http_response = -1;
57 static int hf_http_request = -1;
58
59 static gint ett_http = -1;
60
61 #define TCP_PORT_HTTP                   80
62 #define TCP_PORT_PROXY_HTTP             3128
63 #define TCP_PORT_PROXY_ADMIN_HTTP       3132
64 #define TCP_ALT_PORT_HTTP               8080
65
66 /*
67  * SSDP is implemented atop HTTP (yes, it really *does* run over UDP).
68  */
69 #define TCP_PORT_SSDP                   1900
70 #define UDP_PORT_SSDP                   1900
71
72 /*
73  * Protocols implemented atop HTTP.
74  */
75 typedef enum {
76         PROTO_HTTP,             /* just HTTP */
77         PROTO_SSDP              /* Simple Service Discovery Protocol */
78 } http_proto_t;
79
80 static int is_http_request_or_reply(const u_char *data, int linelen, http_type_t *type);
81
82 static dissector_table_t subdissector_table;
83
84 static void
85 dissect_http(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
86 {
87         http_proto_t    proto;
88         char            *proto_tag;
89         proto_tree      *http_tree = NULL;
90         proto_item      *ti = NULL;
91         gint            offset = 0;
92         const u_char    *line;
93         gint            next_offset;
94         const u_char    *linep, *lineend;
95         int             linelen;
96         u_char          c;
97         http_type_t     http_type;
98         int             datalen;
99
100         switch (pinfo->match_port) {
101
102         case TCP_PORT_SSDP:     /* TCP_PORT_SSDP = UDP_PORT_SSDP */
103                 proto = PROTO_SSDP;
104                 proto_tag = "SSDP";
105                 break;
106
107         default:
108                 proto = PROTO_HTTP;
109                 proto_tag = "HTTP";
110                 break;
111         }
112         
113         if (check_col(pinfo->fd, COL_PROTOCOL))
114                 col_set_str(pinfo->fd, COL_PROTOCOL, proto_tag);
115         if (check_col(pinfo->fd, COL_INFO)) {
116                 /*
117                  * Put the first line from the buffer into the summary
118                  * if it's an HTTP request or reply (but leave out the
119                  * line terminator).
120                  * Otherwise, just call it a continuation.
121                  *
122                  * Note that "tvb_find_line_end()" will return a value that
123                  * is not longer than what's in the buffer, so the
124                  * "tvb_get_ptr()" call won't throw an exception.
125                  */
126                 linelen = tvb_find_line_end(tvb, offset, -1, &next_offset);
127                 line = tvb_get_ptr(tvb, offset, linelen);
128                 http_type = HTTP_OTHERS;        /* type not known yet */
129                 if (is_http_request_or_reply(line, linelen, &http_type))
130                         col_add_str(pinfo->fd, COL_INFO,
131                             format_text(line, linelen));
132                 else
133                         col_set_str(pinfo->fd, COL_INFO, "Continuation");
134         }
135
136         if (tree) {
137                 ti = proto_tree_add_item(tree, proto_http, tvb, offset,
138                     tvb_length_remaining(tvb, offset), FALSE);
139                 http_tree = proto_item_add_subtree(ti, ett_http);
140         }
141
142         /*
143          * Process the packet data, a line at a time.
144          */
145         http_type = HTTP_OTHERS;        /* type not known yet */
146         while (tvb_offset_exists(tvb, offset)) {
147                 /*
148                  * Find the end of the line.
149                  */
150                 linelen = tvb_find_line_end(tvb, offset, -1, &next_offset);
151
152                 /*
153                  * Get a buffer that refers to the line.
154                  */
155                 line = tvb_get_ptr(tvb, offset, linelen);
156                 lineend = line + linelen;
157
158                 /*
159                  * OK, does it look like an HTTP request or response?
160                  */
161                 if (is_http_request_or_reply(line, linelen, &http_type))
162                         goto is_http;
163
164                 /*
165                  * No.  Does it look like a blank line (as would appear
166                  * at the end of an HTTP request)?
167                  */
168                 if (linelen == 0)
169                         goto is_http;
170
171                 /*
172                  * No.  Does it look like a MIME header?
173                  */
174                 linep = line;
175                 while (linep < lineend) {
176                         c = *linep++;
177                         if (!isprint(c))
178                                 break;  /* not printable, not a MIME header */
179                         switch (c) {
180
181                         case '(':
182                         case ')':
183                         case '<':
184                         case '>':
185                         case '@':
186                         case ',':
187                         case ';':
188                         case '\\':
189                         case '"':
190                         case '/':
191                         case '[':
192                         case ']':
193                         case '?':
194                         case '=':
195                         case '{':
196                         case '}':
197                                 /*
198                                  * It's a tspecial, so it's not part of a
199                                  * token, so it's not a field name for the
200                                  * beginning of a MIME header.
201                                  */
202                                 goto not_http;
203
204                         case ':':
205                                 /*
206                                  * This ends the token; we consider this
207                                  * to be a MIME header.
208                                  */
209                                 goto is_http;
210                         }
211                 }
212
213         not_http:
214                 /*
215                  * We don't consider this part of an HTTP request or
216                  * reply, so we don't display it.
217                  * (Yeah, that means we don't display, say, a text/http
218                  * page, but you can get that from the data pane.)
219                  */
220                 break;
221
222         is_http:
223                 /*
224                  * Put this line.
225                  */
226                 if (tree) {
227                         proto_tree_add_text(http_tree, tvb, offset,
228                             next_offset - offset, "%s",
229                             tvb_format_text(tvb, offset, next_offset - offset));
230                 }
231                 offset = next_offset;
232         }
233
234         if (tree) {
235                 switch (http_type) {
236
237                 case HTTP_NOTIFICATION:
238                         proto_tree_add_boolean_hidden(http_tree, 
239                             hf_http_notification, tvb, 0, 0, 1);
240                         break;
241
242                 case HTTP_RESPONSE:
243                         proto_tree_add_boolean_hidden(http_tree, 
244                             hf_http_response, tvb, 0, 0, 1);
245                         break;
246
247                 case HTTP_REQUEST:
248                         proto_tree_add_boolean_hidden(http_tree, 
249                             hf_http_request, tvb, 0, 0, 1);
250                         break;
251
252                 case HTTP_OTHERS:
253                 default:
254                         break;
255                 }
256         }
257
258         datalen = tvb_length_remaining(tvb, offset);
259         if (datalen > 0) {
260                 tvbuff_t *next_tvb = tvb_new_subset(tvb, offset, -1, -1);
261
262                 /*
263                  * OK, has some subdissector asked that they be called
264                  * if something was on some particular port?
265                  */
266                 if (dissector_try_port(subdissector_table, pinfo->match_port,
267                     next_tvb, pinfo, tree)) {
268                         /*
269                          * Yes.  Fix up the top-level item so that it
270                          * doesn't include the stuff for that protocol.
271                          */
272                         if (ti != NULL)
273                                 proto_item_set_len(ti, offset);
274                 } else
275                         dissect_data(tvb, offset, pinfo, http_tree);
276         }
277 }
278
279 /*
280  * XXX - this won't handle HTTP 0.9 replies, but they're all data
281  * anyway.
282  */
283 static int
284 is_http_request_or_reply(const u_char *data, int linelen, http_type_t *type)
285 {
286         /*
287          * From RFC 2774 - An HTTP Extension Framework
288          *
289          * Support the command prefix that identifies the presence of
290          * a "mandatory" header.
291          */
292         if (strncmp(data, "M-", 2) == 0) {
293                 data += 2;
294                 linelen -= 2;
295         }
296
297         /*
298          * From draft-cohen-gena-client-01.txt, available from the uPnP forum:
299          *      NOTIFY, SUBSCRIBE, UNSUBSCRIBE
300          *
301          * From draft-ietf-dasl-protocol-00.txt, a now vanished Microsoft draft:
302          *      SEARCH
303          */
304         if (linelen >= 4) {
305                 if (strncmp(data, "GET ", 4) == 0 ||
306                     strncmp(data, "PUT ", 4) == 0) {
307                         if (*type == HTTP_OTHERS)
308                                 *type = HTTP_REQUEST;
309                         return TRUE;
310                 }
311         }
312         if (linelen >= 5) {
313                 if (strncmp(data, "HEAD ", 5) == 0 ||
314                     strncmp(data, "POST ", 5) == 0) {
315                         if (*type == HTTP_OTHERS)
316                                 *type = HTTP_REQUEST;
317                         return TRUE;
318                 }
319                 if (strncmp(data, "HTTP/", 5) == 0) {
320                         if (*type == HTTP_OTHERS)
321                                 *type = HTTP_RESPONSE;
322                         return TRUE;    /* response */
323                 }
324         }
325         if (linelen >= 6) {
326                 if (strncmp(data, "TRACE ", 6) == 0) {
327                         if (*type == HTTP_OTHERS)
328                                 *type = HTTP_REQUEST;
329                         return TRUE;
330                 }
331         }
332         if (linelen >= 7) {
333                 if (strncmp(data, "DELETE ", 7) == 0) {
334                         if (*type == HTTP_OTHERS)
335                                 *type = HTTP_REQUEST;
336                         return TRUE;
337                 }
338                 if (strncmp(data, "NOTIFY ", 7) == 0 ||
339                     strncmp(data, "SEARCH ", 7) == 0) {
340                         if (*type == HTTP_OTHERS)
341                                 *type = HTTP_NOTIFICATION;
342                         return TRUE;
343                 }
344         }
345         if (linelen >= 8) {
346                 if (strncmp(data, "OPTIONS ", 8) == 0 ||
347                     strncmp(data, "CONNECT ", 8) == 0) {
348                         if (*type == HTTP_OTHERS)
349                                 *type = HTTP_REQUEST;
350                         return TRUE;
351                 }
352         }
353         if (linelen >= 10) {
354                 if (strncmp(data, "SUBSCRIBE ", 10) == 0) {
355                         if (*type == HTTP_OTHERS)
356                                 *type = HTTP_NOTIFICATION;
357                         return TRUE;
358                 }
359         }
360         if (linelen >= 12) {
361                 if (strncmp(data, "UNSUBSCRIBE ", 10) == 0) {
362                         if (*type == HTTP_OTHERS)
363                                 *type = HTTP_NOTIFICATION;
364                         return TRUE;
365                 }
366         }
367         return FALSE;
368 }
369
370 void
371 proto_register_http(void)
372 {
373         static hf_register_info hf[] = {
374             { &hf_http_notification,
375               { "Notification",         "http.notification",  
376                 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
377                 "TRUE if HTTP notification", HFILL }},
378             { &hf_http_response,
379               { "Response",             "http.response",  
380                 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
381                 "TRUE if HTTP response", HFILL }},
382             { &hf_http_request,
383               { "Request",              "http.request",
384                 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
385                 "TRUE if HTTP request", HFILL }},
386         };
387         static gint *ett[] = {
388                 &ett_http,
389         };
390
391         proto_http = proto_register_protocol("Hypertext Transfer Protocol",
392             "HTTP", "http");
393         proto_register_field_array(proto_http, hf, array_length(hf));
394         proto_register_subtree_array(ett, array_length(ett));
395
396         register_dissector("http", dissect_http, proto_http);
397
398         /*
399          * Dissectors shouldn't register themselves in this table;
400          * instead, they should call "http_dissector_add()", and
401          * we'll register the port number they specify as a port
402          * for HTTP, and register them in our subdissector table.
403          *
404          * This only works for protocols such as IPP that run over
405          * HTTP on a specific non-HTTP port.
406          */
407         subdissector_table = register_dissector_table("http.port");
408 }
409
410 /*
411  * Called by dissectors for protocols that run atop HTTP/TCP.
412  */
413 void
414 http_dissector_add(guint32 port, dissector_t dissector, int proto)
415 {
416         /*
417          * Register ourselves as the handler for that port number
418          * over TCP.
419          */
420         dissector_add("tcp.port", port, dissect_http, proto_http);
421
422         /*
423          * And register them in *our* table for that port.
424          */
425         dissector_add("http.port", port, dissector, proto);
426 }
427
428 void
429 proto_reg_handoff_http(void)
430 {
431         dissector_add("tcp.port", TCP_PORT_HTTP, dissect_http, proto_http);
432         dissector_add("tcp.port", TCP_ALT_PORT_HTTP, dissect_http, proto_http);
433         dissector_add("tcp.port", TCP_PORT_PROXY_HTTP, dissect_http,
434             proto_http);
435         dissector_add("tcp.port", TCP_PORT_PROXY_ADMIN_HTTP, dissect_http,
436             proto_http);
437
438         /*
439          * XXX - is there anything to dissect in the body of an SSDP
440          * request or reply?  I.e., should there be an SSDP dissector?
441          */
442         dissector_add("tcp.port", TCP_PORT_SSDP, dissect_http, proto_http);
443         dissector_add("udp.port", UDP_PORT_SSDP, dissect_http, proto_http);
444 }