diff --git a/Makefile.am b/Makefile.am index d1f7aad409..5b187f6252 100644 --- a/Makefile.am +++ b/Makefile.am @@ -24,6 +24,7 @@ ethereal_SOURCES = \ packet-eth.c \ packet-fddi.c \ packet-giop.c \ + packet-http.c \ packet-llc.c \ packet-lpd.c \ packet-ip.c \ diff --git a/Makefile.in b/Makefile.in index 762e61e239..9d688f9431 100644 --- a/Makefile.in +++ b/Makefile.in @@ -99,6 +99,7 @@ ethereal_SOURCES = \ packet-eth.c \ packet-fddi.c \ packet-giop.c \ + packet-http.c \ packet-llc.c \ packet-lpd.c \ packet-ip.c \ @@ -184,11 +185,12 @@ LIBS = @LIBS@ ethereal_OBJECTS = capture.o column.o ethereal.o ethertype.o file.o \ filter.o follow.o menu.o packet.o packet-aarp.o packet-arp.o \ packet-atalk.o packet-bootp.o packet-cdp.o packet-data.o packet-dns.o \ -packet-eth.o packet-fddi.o packet-giop.o packet-llc.o packet-lpd.o \ -packet-ip.o packet-ipv6.o packet-ipx.o packet-nbipx.o packet-nbns.o \ -packet-ncp.o packet-null.o packet-osi.o packet-ospf.o packet-ppp.o \ -packet-raw.o packet-rip.o packet-tcp.o packet-tr.o packet-trmac.o \ -packet-udp.o packet-vines.o prefs.o print.o ps.o resolv.o util.o +packet-eth.o packet-fddi.o packet-giop.o packet-http.o packet-llc.o \ +packet-lpd.o packet-ip.o packet-ipv6.o packet-ipx.o packet-nbipx.o \ +packet-nbns.o packet-ncp.o packet-null.o packet-osi.o packet-ospf.o \ +packet-ppp.o packet-raw.o packet-rip.o packet-tcp.o packet-tr.o \ +packet-trmac.o packet-udp.o packet-vines.o prefs.o print.o ps.o \ +resolv.o util.o ethereal_LDFLAGS = CFLAGS = @CFLAGS@ COMPILE = $(CC) $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) @@ -214,15 +216,15 @@ DEP_FILES = .deps/capture.P .deps/column.P .deps/ethereal.P \ .deps/menu.P .deps/packet-aarp.P .deps/packet-arp.P \ .deps/packet-atalk.P .deps/packet-bootp.P .deps/packet-cdp.P \ .deps/packet-data.P .deps/packet-dns.P .deps/packet-eth.P \ -.deps/packet-fddi.P .deps/packet-giop.P .deps/packet-ip.P \ -.deps/packet-ipv6.P .deps/packet-ipx.P .deps/packet-llc.P \ -.deps/packet-lpd.P .deps/packet-nbipx.P .deps/packet-nbns.P \ -.deps/packet-ncp.P .deps/packet-null.P .deps/packet-osi.P \ -.deps/packet-ospf.P .deps/packet-ppp.P .deps/packet-raw.P \ -.deps/packet-rip.P .deps/packet-tcp.P .deps/packet-tr.P \ -.deps/packet-trmac.P .deps/packet-udp.P .deps/packet-vines.P \ -.deps/packet.P .deps/prefs.P .deps/print.P .deps/ps.P .deps/resolv.P \ -.deps/snprintf.P .deps/util.P +.deps/packet-fddi.P .deps/packet-giop.P .deps/packet-http.P \ +.deps/packet-ip.P .deps/packet-ipv6.P .deps/packet-ipx.P \ +.deps/packet-llc.P .deps/packet-lpd.P .deps/packet-nbipx.P \ +.deps/packet-nbns.P .deps/packet-ncp.P .deps/packet-null.P \ +.deps/packet-osi.P .deps/packet-ospf.P .deps/packet-ppp.P \ +.deps/packet-raw.P .deps/packet-rip.P .deps/packet-tcp.P \ +.deps/packet-tr.P .deps/packet-trmac.P .deps/packet-udp.P \ +.deps/packet-vines.P .deps/packet.P .deps/prefs.P .deps/print.P \ +.deps/ps.P .deps/resolv.P .deps/snprintf.P .deps/util.P SOURCES = $(ethereal_SOURCES) $(EXTRA_ethereal_SOURCES) OBJECTS = $(ethereal_OBJECTS) diff --git a/packet-http.c b/packet-http.c new file mode 100644 index 0000000000..86a5ae9cc7 --- /dev/null +++ b/packet-http.c @@ -0,0 +1,215 @@ +/* packet-http.c + * Routines for HTTP packet disassembly + * + * Guy Harris + * + * $Id: packet-http.c,v 1.1 1999/02/12 09:03:40 guy Exp $ + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * + * 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. + * + * + */ + +#include "config.h" + +#include + +#include +#include +#include + +#ifdef HAVE_SYS_TYPES_H +#include +#endif + +#ifdef HAVE_NETINET_IN_H +#include +#endif + +#include "ethereal.h" +#include "packet.h" + +static int is_http_request_or_reply(const u_char *data, int linelen); + +void dissect_http(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) +{ + GtkWidget *http_tree, *ti; + const u_char *data, *dataend; + const u_char *linep, *lineend; + int linelen; + u_char c; + + data = &pd[offset]; + dataend = data + END_OF_FRAME; + + if (check_col(fd, COL_PROTOCOL)) + col_add_str(fd, COL_PROTOCOL, "HTTP"); + if (check_col(fd, COL_INFO)) { + /* + * Put the first line from the buffer into the summary, + * if it's an HTTP request or reply. + * Otherwise, just call it a continuation. + */ + lineend = find_line_end(data, dataend); + linelen = lineend - data; + if (is_http_request_or_reply(data, linelen)) + col_add_str(fd, COL_INFO, format_line(data, linelen)); + else + col_add_str(fd, COL_INFO, "Continuation"); + } + + if (tree) { + ti = add_item_to_tree(GTK_WIDGET(tree), offset, + END_OF_FRAME, + "Hypertext Transfer Protocol"); + http_tree = gtk_tree_new(); + add_subtree(ti, http_tree, ETT_HTTP); + + while (data < dataend) { + /* + * Find the end of the line. + */ + lineend = find_line_end(data, dataend); + linelen = lineend - data; + + /* + * OK, does it look like an HTTP request or + * response? + */ + if (is_http_request_or_reply(data, linelen)) + goto is_http; + + /* + * No. Does it look like a blank line (as would + * appear at the end of an HTTP request)? + */ + if (linelen == 1) { + if (*data == '\n') + goto is_http; + } + if (linelen == 2) { + if (strncmp(data, "\r\n", 2) == 0 || + strncmp(data, "\n\r", 2) == 0) + goto is_http; + } + + /* + * No. Does it look like a MIME header? + */ + linep = data; + while (linep < lineend) { + c = *linep++; + if (!isprint(c)) + break; /* not printable, not a MIME header */ + switch (c) { + + case '(': + case ')': + case '<': + case '>': + case '@': + case ',': + case ';': + case '\\': + case '"': + case '/': + case '[': + case ']': + case '?': + case '=': + case '{': + case '}': + /* + * It's a tspecial, so it's not + * part of a token, so it's not + * a field name for the beginning + * of a MIME header. + */ + goto not_http; + + case ':': + /* + * This ends the token; we consider + * this to be a MIME header. + */ + goto is_http; + } + } + + not_http: + /* + * We don't consider this part of an HTTP request or + * reply, so we don't display it. + * (Yeah, that means we don't display, say, a + * text/http page, but you can get that from the + * data pane.) + */ + break; + + is_http: + /* + * Put this line. + */ + add_item_to_tree(http_tree, offset, linelen, "%s", + format_line(data, linelen)); + offset += linelen; + data = lineend; + } + + if (data < dataend) { + add_item_to_tree(http_tree, offset, END_OF_FRAME, + "Data (%d bytes)", END_OF_FRAME); + } + } +} + +/* + * XXX - this won't handle HTTP 0.9 replies, but they're all data + * anyway. + */ +static int +is_http_request_or_reply(const u_char *data, int linelen) +{ + if (linelen >= 3) { + if (strncasecmp(data, "GET", 3) == 0 || + strncasecmp(data, "PUT", 3) == 0) + return TRUE; + } + if (linelen >= 4) { + if (strncasecmp(data, "HEAD", 4) == 0 || + strncasecmp(data, "POST", 4) == 0) + return TRUE; + } + if (linelen >= 5) { + if (strncasecmp(data, "TRACE", 5) == 0) + return TRUE; + if (strncasecmp(data, "HTTP/", 5) == 0) + return TRUE; /* response */ + } + if (linelen >= 6) { + if (strncasecmp(data, "DELETE", 6) == 0) + return TRUE; + } + if (linelen >= 7) { + if (strncasecmp(data, "OPTIONS", 7) == 0) + return TRUE; + } + return FALSE; +} diff --git a/packet-tcp.c b/packet-tcp.c index 1920b9ef78..6a95973a9f 100644 --- a/packet-tcp.c +++ b/packet-tcp.c @@ -1,7 +1,7 @@ /* packet-tcp.c * Routines for TCP packet disassembly * - * $Id: packet-tcp.c,v 1.14 1999/02/08 20:02:34 gram Exp $ + * $Id: packet-tcp.c,v 1.15 1999/02/12 09:03:41 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -378,13 +378,17 @@ dissect_tcp(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) { /* Skip over header + options */ offset += hlen; - /* until we decode those options, I'll check the packet length - to see if there's more data. -- gilbert */ + /* Check the packet length to see if there's more data + (it could be an ACK-only packet) */ if (fd->cap_len > offset) { switch(MIN(th.th_sport, th.th_dport)) { case TCP_PORT_PRINTER: dissect_lpd(pd, offset, fd, tree); break; + case TCP_PORT_HTTP: + case TCP_ALT_PORT_HTTP: + dissect_http(pd, offset, fd, tree); + break; default: /* check existence of high level protocols */ diff --git a/packet.c b/packet.c index efe9c29a57..f4c32b5848 100644 --- a/packet.c +++ b/packet.c @@ -1,7 +1,7 @@ /* packet.c * Routines for packet disassembly * - * $Id: packet.c,v 1.19 1999/01/28 21:29:36 gram Exp $ + * $Id: packet.c,v 1.20 1999/02/12 09:03:41 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -227,6 +227,138 @@ add_item_to_tree(GtkWidget *tree, gint start, gint len, return ti; } +/* + * Given a pointer into a data buffer, and to the end of the buffer, + * find the end of the (putative) line at that position in the data + * buffer. + */ +const u_char * +find_line_end(const u_char *data, const u_char *dataend) +{ + const u_char *lineend; + + lineend = memchr(data, '\n', dataend - data); + if (lineend == NULL) { + /* + * No newline - line is probably continued in next TCP segment. + */ + lineend = dataend; + } else { + /* + * Is the newline preceded by a carriage return? + * (Perhaps it's supposed to be, but that's not guaranteed....) + */ + if (lineend > data && *(lineend - 1) != '\r') { + /* + * No. I seem to remember that we once saw lines + * ending with LF-CR in an HTTP request or response, + * so check if it's *followed* by a carriage return. + */ + if (lineend < (dataend - 1) && *(lineend + 1) == '\r') { + /* + * It's ; say it ends with the CR. + */ + lineend++; + } + } + + /* + * Point to the character after the last character. + */ + lineend++; + } + return lineend; +} + +#define MAX_COLUMNS_LINE_DETAIL 62 + +gchar * +format_line(const u_char *line, int len) +{ + static gchar linebuf[MAX_COLUMNS_LINE_DETAIL + 3 + 4 + 1]; + gchar *linebufp; + int column; + const u_char *lineend = line + len; + u_char c; + int i; + + column = 0; + linebufp = &linebuf[0]; + while (line < lineend) { + if (column >= MAX_COLUMNS_LINE_DETAIL) { + /* + * Put "..." and quit. + */ + strcpy(linebufp, " ..."); + break; + } + c = *line++; + if (isprint(c)) { + *linebufp++ = c; + column++; + } else { + *linebufp++ = '\\'; + column++; + switch (c) { + + case '\\': + *linebufp++ = '\\'; + column++; + break; + + case '\a': + *linebufp++ = 'a'; + column++; + break; + + case '\b': + *linebufp++ = 'b'; + column++; + break; + + case '\f': + *linebufp++ = 'f'; + column++; + break; + + case '\n': + *linebufp++ = 'n'; + column++; + break; + + case '\r': + *linebufp++ = 'r'; + column++; + break; + + case '\t': + *linebufp++ = 't'; + column++; + break; + + case '\v': + *linebufp++ = 'v'; + column++; + break; + + default: + i = (c>>6)&03; + *linebufp++ = i + '0'; + column++; + i = (c>>3)&07; + *linebufp++ = i + '0'; + column++; + i = (c>>0)&07; + *linebufp++ = i + '0'; + column++; + break; + } + } + } + *linebufp = '\0'; + return linebuf; +} + void set_item_len(GtkWidget *ti, gint len) { diff --git a/packet.h b/packet.h index d3d29cdf6f..07e2145ad1 100644 --- a/packet.h +++ b/packet.h @@ -1,7 +1,7 @@ /* packet.h * Definitions for packet disassembly structures and routines * - * $Id: packet.h,v 1.36 1999/02/09 00:35:38 guy Exp $ + * $Id: packet.h,v 1.37 1999/02/12 09:03:40 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -369,7 +369,9 @@ typedef struct _e_udphdr { /* TCP Ports */ -#define TCP_PORT_PRINTER 515 +#define TCP_PORT_HTTP 80 +#define TCP_PORT_PRINTER 515 +#define TCP_ALT_PORT_HTTP 8080 /* Tree types. Each dissect_* routine should have one for each add_subtree() call. */ @@ -449,6 +451,7 @@ enum { ETT_GIOP, ETT_NBDGM, ETT_CDP, + ETT_HTTP, NUM_TREE_TYPES /* last item number plus one */ }; @@ -501,6 +504,8 @@ GtkWidget* add_item_to_tree(GtkWidget *, gint, gint, gchar *, ...) #else GtkWidget* add_item_to_tree(GtkWidget *, gint, gint, gchar *, ...); #endif +const u_char *find_line_end(const u_char *data, const u_char *dataend); +gchar* format_line(const u_char *line, int len); void set_item_len(GtkWidget *, gint); gchar* val_to_str(guint32, const value_string *, const char *); gchar* match_strval(guint32, const value_string*); @@ -567,6 +572,7 @@ void dissect_data(const u_char *, int, frame_data *, GtkTree *); void dissect_ddp(const u_char *, int, frame_data *, GtkTree *); void dissect_dns(const u_char *, int, frame_data *, GtkTree *); void dissect_giop(const u_char *, int, frame_data *, GtkTree *); +void dissect_http(const u_char *, int, frame_data *, GtkTree *); void dissect_icmp(const u_char *, int, frame_data *, GtkTree *); void dissect_igmp(const u_char *, int, frame_data *, GtkTree *); void dissect_ip(const u_char *, int, frame_data *, GtkTree *);