diff --git a/packet-ip.c b/packet-ip.c index c3a73e6395..011d469b7e 100644 --- a/packet-ip.c +++ b/packet-ip.c @@ -1,7 +1,7 @@ /* packet-ip.c * Routines for IP and miscellaneous IP protocol packet disassembly * - * $Id: packet-ip.c,v 1.6 1998/10/10 18:23:42 gerald Exp $ + * $Id: packet-ip.c,v 1.7 1998/10/13 05:40:03 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -47,11 +47,364 @@ extern packet_info pi; +static void +dissect_ipopt_security(GtkWidget *opt_tree, const char *name, + const u_char *opd, int offset, guint optlen) +{ + GtkWidget *field_tree = NULL, *tf; + guint val; + gchar *secl_str; + static value_string secl_vals[] = { + {IPSEC_UNCLASSIFIED, "Unclassified"}, + {IPSEC_CONFIDENTIAL, "Confidential"}, + {IPSEC_EFTO, "EFTO" }, + {IPSEC_MMMM, "MMMM" }, + {IPSEC_RESTRICTED, "Restricted" }, + {IPSEC_SECRET, "Secret" }, + {IPSEC_TOPSECRET, "Top secret" }, + {IPSEC_RESERVED1, "Reserved" }, + {IPSEC_RESERVED2, "Reserved" }, + {IPSEC_RESERVED3, "Reserved" }, + {IPSEC_RESERVED4, "Reserved" }, + {IPSEC_RESERVED5, "Reserved" }, + {IPSEC_RESERVED6, "Reserved" }, + {IPSEC_RESERVED7, "Reserved" }, + {IPSEC_RESERVED8, "Reserved" } }; +#define N_SECL_VALS (sizeof secl_vals / sizeof secl_vals[0]) + + + tf = add_item_to_tree(opt_tree, offset, optlen, "%s:", name); + field_tree = gtk_tree_new(); + add_subtree(tf, field_tree, ETT_IP_OPTION_SEC); + offset += 2; + + val = pntohs(opd); + if ((secl_str = match_strval(val, secl_vals, N_SECL_VALS))) + add_item_to_tree(field_tree, offset, 2, + "Security: %s", secl_str); + else + add_item_to_tree(field_tree, offset, 2, + "Security: Unknown (0x%x)", val); + offset += 2; + opd += 2; + + val = pntohs(opd); + add_item_to_tree(field_tree, offset, 2, + "Compartments: %d", val); + offset += 2; + opd += 2; + + add_item_to_tree(field_tree, offset, 2, + "Handling restrictions: %c%c", opd[0], opd[1]); + offset += 2; + opd += 2; + + add_item_to_tree(field_tree, offset, 3, + "Transmission control code: %c%c%c", opd[0], opd[1], opd[2]); +} + +static void +dissect_ipopt_route(GtkWidget *opt_tree, const char *name, + const u_char *opd, int offset, guint optlen) +{ + GtkWidget *field_tree = NULL, *tf; + int ptr; + int optoffset = 0; + struct in_addr addr; + + tf = add_item_to_tree(opt_tree, offset, optlen, "%s (%d bytes)", name, + optlen); + field_tree = gtk_tree_new(); + add_subtree(tf, field_tree, ETT_IP_OPTION_ROUTE); + + optoffset += 2; /* skip past type and length */ + optlen -= 2; /* subtract size of type and length */ + + ptr = *opd; + add_item_to_tree(field_tree, offset + optoffset, 1, + "Pointer: %d%s", ptr, + ((ptr < 4) ? " (points before first address)" : + ((ptr & 3) ? " (points to middle of address)" : ""))); + optoffset++; + opd++; + optlen--; + ptr--; /* ptr is 1-origin */ + + while (optlen > 0) { + if (optlen < 4) { + add_item_to_tree(field_tree, offset, optlen, + "(suboption would go past end of option)"); + break; + } + + /* Avoids alignment problems on many architectures. */ + memcpy((char *)&addr, (char *)opd, sizeof(addr)); + + add_item_to_tree(field_tree, offset + optoffset, 4, + "%s%s", + ((addr.s_addr == 0) ? "-" : (char *)get_hostname(addr.s_addr)), + ((optoffset == ptr) ? " <- (current)" : "")); + optoffset += 4; + opd += 4; + optlen -= 4; + } +} + +static void +dissect_ipopt_sid(GtkWidget *opt_tree, const char *name, const u_char *opd, + int offset, guint optlen) +{ + add_item_to_tree(opt_tree, offset, optlen, + "%s: %d", name, pntohs(opd)); + return; +} + +static void +dissect_ipopt_timestamp(GtkWidget *opt_tree, const char *name, const u_char *opd, + int offset, guint optlen) +{ + GtkWidget *field_tree = NULL, *tf; + int ptr; + int optoffset = 0; + int flg; + gchar *flg_str; + static value_string flag_vals[] = { + {IPOPT_TS_TSONLY, "Time stamps only" }, + {IPOPT_TS_TSANDADDR, "Time stamp and address" }, + {IPOPT_TS_PRESPEC, "Time stamps for prespecified addresses"} }; +#define N_FLAG_VALS (sizeof flag_vals / sizeof flag_vals[0]) + + struct in_addr addr; + guint ts; + + tf = add_item_to_tree(opt_tree, offset, optlen, "%s:", name); + field_tree = gtk_tree_new(); + add_subtree(tf, field_tree, ETT_IP_OPTION_TIMESTAMP); + + optoffset += 2; /* skip past type and length */ + optlen -= 2; /* subtract size of type and length */ + + ptr = *opd; + add_item_to_tree(field_tree, offset + optoffset, 1, + "Pointer: %d%s", ptr, + ((ptr < 5) ? " (points before first address)" : + (((ptr - 1) & 3) ? " (points to middle of address)" : ""))); + optoffset++; + opd++; + optlen--; + ptr--; /* ptr is 1-origin */ + + flg = *opd; + add_item_to_tree(field_tree, offset + optoffset, 1, + "Overflow: %d", flg >> 4); + flg &= 0xF; + if ((flg_str = match_strval(flg, flag_vals, N_FLAG_VALS))) + add_item_to_tree(field_tree, offset + optoffset, 1, + "Flag: %s", flg_str); + else + add_item_to_tree(field_tree, offset + optoffset, 1, + "Flag: Unknown (0x%x)", flg); + optoffset++; + opd++; + optlen--; + + while (optlen > 0) { + if (flg == IPOPT_TS_TSANDADDR) { + if (optlen < 4) { + add_item_to_tree(field_tree, offset + optoffset, optlen, + "(suboption would go past end of option)"); + break; + } + /* XXX - check whether it goes past end of packet */ + ts = pntohl(opd); + opd += 4; + optlen -= 4; + if (optlen < 4) { + add_item_to_tree(field_tree, offset + optoffset, optlen, + "(suboption would go past end of option)"); + break; + } + /* XXX - check whether it goes past end of packet */ + memcpy((char *)&addr, (char *)opd, sizeof(addr)); + opd += 4; + optlen -= 4; + add_item_to_tree(field_tree, offset, 8, + "Address = %s, time stamp = %u", + ((addr.s_addr == 0) ? "-" : (char *)get_hostname(addr.s_addr)), + ts); + optoffset += 8; + } else { + if (optlen < 4) { + add_item_to_tree(field_tree, offset + optoffset, optlen, + "(suboption would go past end of option)"); + break; + } + /* XXX - check whether it goes past end of packet */ + ts = pntohl(opd); + opd += 4; + optlen -= 4; + add_item_to_tree(field_tree, offset + optoffset, 4, + "Time stamp = %u", ts); + optoffset += 4; + } + } +} + +static ip_tcp_opt ipopts[] = { + { + IPOPT_END, + "EOL", + NO_LENGTH, + 0, + NULL, + }, + { + IPOPT_NOOP, + "NOP", + NO_LENGTH, + 0, + NULL, + }, + { + IPOPT_SEC, + "Security", + FIXED_LENGTH, + IPOLEN_SEC, + dissect_ipopt_security + }, + { + IPOPT_SSRR, + "Strict source route", + VARIABLE_LENGTH, + IPOLEN_SSRR_MIN, + dissect_ipopt_route + }, + { + IPOPT_LSRR, + "Loose source route", + VARIABLE_LENGTH, + IPOLEN_LSRR_MIN, + dissect_ipopt_route + }, + { + IPOPT_RR, + "Record route", + VARIABLE_LENGTH, + IPOLEN_RR_MIN, + dissect_ipopt_route + }, + { + IPOPT_SID, + "Stream identifier", + FIXED_LENGTH, + IPOLEN_SID, + dissect_ipopt_sid + }, + { + IPOPT_TIMESTAMP, + "Time stamp", + VARIABLE_LENGTH, + IPOLEN_TIMESTAMP_MIN, + dissect_ipopt_timestamp + } +}; + +#define N_IP_OPTS (sizeof ipopts / sizeof ipopts[0]) + +/* Dissect the IP or TCP options in a packet. */ +void +dissect_ip_tcp_options(GtkWidget *opt_tree, const u_char *opd, int offset, + guint length, ip_tcp_opt *opttab, int nopts, int eol) +{ + u_char opt; + ip_tcp_opt *optp; + guint len; + + while (length > 0) { + opt = *opd++; + for (optp = &opttab[0]; optp < &opttab[nopts]; optp++) { + if (optp->optcode == opt) + break; + } + if (optp == &opttab[nopts]) { + add_item_to_tree(opt_tree, offset, 1, "Unknown"); + /* We don't know how long this option is, so we don't know how much + of it to skip, so we just bail. */ + return; + } + --length; /* account for type byte */ + if (optp->len_type != NO_LENGTH) { + /* Option has a length. Is it in the packet? */ + if (length == 0) { + /* Bogus - packet must at least include option code byte and + length byte! */ + add_item_to_tree(opt_tree, offset, 1, + "%s (length byte past end of header)", optp->name); + return; + } + len = *opd++; /* total including type, len */ + --length; /* account for length byte */ + if (len < 2) { + /* Bogus - option length is too short to include option code and + option length. */ + add_item_to_tree(opt_tree, offset, 2, + "%s (with too-short option length = %u bytes)", optp->name, 2); + return; + } else if (len - 2 > length) { + /* Bogus - option goes past the end of the header. */ + add_item_to_tree(opt_tree, offset, length, + "%s (option goes past end of header)", optp->name); + return; + } else if (optp->len_type == FIXED_LENGTH && len != optp->optlen) { + /* Bogus - option length isn't what it's supposed to be for this + option. */ + add_item_to_tree(opt_tree, offset, len, + "%s (with option length = %u bytes; should be %u)", optp->name, + len, optp->optlen); + return; + } else if (optp->len_type == VARIABLE_LENGTH && len < optp->optlen) { + /* Bogus - option length is less than what it's supposed to be for + this option. */ + add_item_to_tree(opt_tree, offset, len, + "%s (with option length = %u bytes; should be >= %u)", optp->name, + len, optp->optlen); + return; + } else { + if (optp->dissect != NULL) { + /* Option has a dissector. */ + (*optp->dissect)(opt_tree, optp->name, opd, offset, len); + } else { + /* Option has no data, hence no dissector. */ + add_item_to_tree(opt_tree, offset, len, "%s", optp->name); + } + len -= 2; /* subtract size of type and length */ + offset += 2 + len; + } + opd += len; + length -= len; + } else { + add_item_to_tree(opt_tree, offset, 1, "%s", optp->name); + offset += 1; + } + if (opt == eol) + break; + } +} + void dissect_ip(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) { e_ip iph; - GtkWidget *ip_tree, *ti; + GtkWidget *ip_tree, *ti, *field_tree, *tf; gchar tos_str[32]; + guint hlen, optlen; + gchar *proto_str; + static value_string proto_vals[] = { {IP_PROTO_ICMP, "ICMP"}, + {IP_PROTO_IGMP, "IGMP"}, + {IP_PROTO_TCP, "TCP" }, + {IP_PROTO_UDP, "UDP" }, + {IP_PROTO_OSPF, "OSPF"} }; +#define N_PROTO_VALS (sizeof proto_vals / sizeof proto_vals[0]) + /* To do: check for runts, errs, etc. */ /* Avoids alignment problems on many architectures. */ @@ -60,6 +413,8 @@ dissect_ip(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) { iph.ip_id = ntohs(iph.ip_id); iph.ip_off = ntohs(iph.ip_off); iph.ip_sum = ntohs(iph.ip_sum); + + hlen = iph.ip_hl * 4; /* IP header length, in bytes */ if (fd->win_info[COL_NUM]) { switch (iph.ip_p) { @@ -97,17 +452,16 @@ dissect_ip(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) { strcpy(tos_str, "Minimize cost"); break; default: - strcpy(tos_str, "Unknon. Malformed?"); + strcpy(tos_str, "Unknown. Malformed?"); break; } if (tree) { - ti = add_item_to_tree(GTK_WIDGET(tree), offset, (iph.ip_hl * 4), - "Internet Protocol"); + ti = add_item_to_tree(GTK_WIDGET(tree), offset, hlen, "Internet Protocol"); ip_tree = gtk_tree_new(); add_subtree(ti, ip_tree, ETT_IP); add_item_to_tree(ip_tree, offset, 1, "Version: %d", iph.ip_v); - add_item_to_tree(ip_tree, offset, 1, "Header length: %d", iph.ip_hl); + add_item_to_tree(ip_tree, offset, 1, "Header length: %d bytes", hlen); add_item_to_tree(ip_tree, offset + 1, 1, "Type of service: 0x%02x (%s)", iph.ip_tos, tos_str); add_item_to_tree(ip_tree, offset + 2, 2, "Total length: %d", iph.ip_len); @@ -115,17 +469,33 @@ dissect_ip(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) { iph.ip_id); /* To do: add flags */ add_item_to_tree(ip_tree, offset + 6, 2, "Fragment offset: %d", - iph.ip_off & 0x1fff); + iph.ip_off & IP_OFFSET); add_item_to_tree(ip_tree, offset + 8, 1, "Time to live: %d", iph.ip_ttl); - add_item_to_tree(ip_tree, offset + 9, 1, "Protocol: 0x%02x", - iph.ip_p); + if ((proto_str = match_strval(iph.ip_p, proto_vals, N_PROTO_VALS))) + add_item_to_tree(ip_tree, offset + 9, 1, "Protocol: %s", proto_str); + else + add_item_to_tree(ip_tree, offset + 9, 1, "Protocol: Unknown (%x)", + iph.ip_p); add_item_to_tree(ip_tree, offset + 10, 2, "Header checksum: 0x%04x", iph.ip_sum); add_item_to_tree(ip_tree, offset + 12, 4, "Source address: %s", get_hostname(iph.ip_src)); add_item_to_tree(ip_tree, offset + 16, 4, "Destination address: %s", get_hostname(iph.ip_dst)); + + /* Decode IP options, if any. */ + if (hlen > sizeof (e_ip)) { + /* There's more than just the fixed-length header. Decode the + options. */ + optlen = hlen - sizeof (e_ip); /* length of options, in bytes */ + tf = add_item_to_tree(ip_tree, offset + 20, optlen, + "Options: (%d bytes)", optlen); + field_tree = gtk_tree_new(); + add_subtree(tf, field_tree, ETT_IP_OPTIONS); + dissect_ip_tcp_options(field_tree, &pd[offset + 20], offset + 20, optlen, + ipopts, N_IP_OPTS, IPOPT_END); + } } pi.srcip = ip_to_str( (guint8 *) &iph.ip_src); @@ -135,7 +505,7 @@ dissect_ip(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) { pi.iphdrlen = iph.ip_hl; pi.ip_src = iph.ip_src; - offset += iph.ip_hl * 4; + offset += hlen; switch (iph.ip_p) { case IP_PROTO_ICMP: dissect_icmp(pd, offset, fd, tree); diff --git a/packet-tcp.c b/packet-tcp.c index 635f7f17de..97d9f02e3b 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.4 1998/09/27 22:12:38 gerald Exp $ + * $Id: packet-tcp.c,v 1.5 1998/10/13 05:40:04 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -46,14 +46,185 @@ extern FILE* data_out_file; extern packet_info pi; +static void +dissect_tcpopt_maxseg(GtkWidget *opt_tree, const char *name, const u_char *opd, + int offset, guint optlen) +{ + add_item_to_tree(opt_tree, offset, optlen, + "%s: %u bytes", name, pntohs(opd)); +} + +static void +dissect_tcpopt_wscale(GtkWidget *opt_tree, const char *name, const u_char *opd, + int offset, guint optlen) +{ + add_item_to_tree(opt_tree, offset, optlen, + "%s: %u bytes", name, *opd); +} + +static void +dissect_tcpopt_sack(GtkWidget *opt_tree, const char *name, const u_char *opd, + int offset, guint optlen) +{ + GtkWidget *field_tree = NULL, *tf; + guint leftedge, rightedge; + + tf = add_item_to_tree(opt_tree, offset, optlen, "%s:", name); + offset += 2; /* skip past type and length */ + optlen -= 2; /* subtract size of type and length */ + while (optlen > 0) { + if (field_tree == NULL) { + /* Haven't yet made a subtree out of this option. Do so. */ + field_tree = gtk_tree_new(); + add_subtree(tf, field_tree, ETT_TCP_OPTION_SACK); + } + if (optlen < 4) { + add_item_to_tree(field_tree, offset, optlen, + "(suboption would go past end of option)"); + break; + } + /* XXX - check whether it goes past end of packet */ + leftedge = pntohl(opd); + opd += 4; + optlen -= 4; + if (optlen < 4) { + add_item_to_tree(field_tree, offset, optlen, + "(suboption would go past end of option)"); + break; + } + /* XXX - check whether it goes past end of packet */ + rightedge = pntohl(opd); + opd += 4; + optlen -= 4; + add_item_to_tree(field_tree, offset, 8, + "left edge = %u, right edge = %u", leftedge, rightedge); + offset += 8; + } +} + +static void +dissect_tcpopt_echo(GtkWidget *opt_tree, const char *name, const u_char *opd, + int offset, guint optlen) +{ + add_item_to_tree(opt_tree, offset, optlen, + "%s: %u", name, pntohl(opd)); +} + +static void +dissect_tcpopt_timestamp(GtkWidget *opt_tree, const char *name, + const u_char *opd, int offset, guint optlen) +{ + add_item_to_tree(opt_tree, offset, optlen, + "%s: tsval %u, tsecr %u", name, pntohl(opd), pntohl(opd + 4)); +} + +static void +dissect_tcpopt_cc(GtkWidget *opt_tree, const char *name, const u_char *opd, + int offset, guint optlen) +{ + add_item_to_tree(opt_tree, offset, optlen, + "%s: %u", name, pntohl(opd)); +} + +static ip_tcp_opt tcpopts[] = { + { + TCPOPT_EOL, + "EOL", + NO_LENGTH, + 0, + NULL, + }, + { + TCPOPT_NOP, + "NOP", + NO_LENGTH, + 0, + NULL, + }, + { + TCPOPT_MSS, + "Maximum segment size", + FIXED_LENGTH, + TCPOLEN_MSS, + dissect_tcpopt_maxseg + }, + { + TCPOPT_WINDOW, + "Window scale", + FIXED_LENGTH, + TCPOLEN_WINDOW, + dissect_tcpopt_wscale + }, + { + TCPOPT_SACK_PERM, + "SACK permitted", + FIXED_LENGTH, + TCPOLEN_SACK_PERM, + NULL, + }, + { + TCPOPT_SACK, + "SACK", + VARIABLE_LENGTH, + TCPOLEN_SACK_MIN, + dissect_tcpopt_sack + }, + { + TCPOPT_ECHO, + "Echo", + FIXED_LENGTH, + TCPOLEN_ECHO, + dissect_tcpopt_echo + }, + { + TCPOPT_ECHOREPLY, + "Echo reply", + FIXED_LENGTH, + TCPOLEN_ECHOREPLY, + dissect_tcpopt_echo + }, + { + TCPOPT_TIMESTAMP, + "Time stamp", + FIXED_LENGTH, + TCPOLEN_TIMESTAMP, + dissect_tcpopt_timestamp + }, + { + TCPOPT_CC, + "CC", + FIXED_LENGTH, + TCPOLEN_CC, + dissect_tcpopt_cc + }, + { + TCPOPT_CCNEW, + "CC.NEW", + FIXED_LENGTH, + TCPOPT_CCNEW, + dissect_tcpopt_cc + }, + { + TCPOPT_CCECHO, + "CC.ECHO", + FIXED_LENGTH, + TCPOLEN_CCECHO, + dissect_tcpopt_cc + } +}; + +#define N_TCP_OPTS (sizeof tcpopts / sizeof tcpopts[0]) + void dissect_tcp(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) { e_tcphdr th; - GtkWidget *tcp_tree, *ti; + GtkWidget *tcp_tree, *ti, *field_tree, *tf; gchar flags[64] = ""; gchar *fstr[] = {"FIN", "SYN", "RST", "PSH", "ACK", "URG"}; gint fpos = 0, i; guint bpos; + guint hlen; + guint optlen; /* To do: Check for {cap len,pkt len} < struct len */ /* Avoids alignment problems on many architectures. */ @@ -85,51 +256,65 @@ dissect_tcp(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) { th.th_sport, th.th_dport); } + hlen = th.th_off * 4; /* TCP header length, in bytes */ + if (tree) { - ti = add_item_to_tree(GTK_WIDGET(tree), offset, 20, + ti = add_item_to_tree(GTK_WIDGET(tree), offset, hlen, "Transmission Control Protocol"); tcp_tree = gtk_tree_new(); add_subtree(ti, tcp_tree, ETT_TCP); add_item_to_tree(tcp_tree, offset, 2, "Source port: %d", th.th_sport); add_item_to_tree(tcp_tree, offset + 2, 2, "Destination port: %d", th.th_dport); - add_item_to_tree(tcp_tree, offset + 4, 4, "Sequence number: 0x%08x", + add_item_to_tree(tcp_tree, offset + 4, 4, "Sequence number: %u", th.th_seq); - add_item_to_tree(tcp_tree, offset + 8, 4, "Acknowledgement number: 0x%08x", - th.th_ack); - add_item_to_tree(tcp_tree, offset + 12, 1, "Header length: %d", th.th_off); + if (th.th_flags & TH_ACK) + add_item_to_tree(tcp_tree, offset + 8, 4, "Acknowledgement number: %u", + th.th_ack); + add_item_to_tree(tcp_tree, offset + 12, 1, "Header length: %d bytes", hlen); add_item_to_tree(tcp_tree, offset + 13, 1, "Flags: %s", flags); add_item_to_tree(tcp_tree, offset + 14, 2, "Window size: %d", th.th_win); add_item_to_tree(tcp_tree, offset + 16, 2, "Checksum: 0x%04x", th.th_sum); - add_item_to_tree(tcp_tree, offset + 18, 2, "Urgent pointer: 0x%04x", - th.th_urp); - /* To do: TCP options */ + if (th.th_flags & TH_URG) + add_item_to_tree(tcp_tree, offset + 18, 2, "Urgent pointer: 0x%04x", + th.th_urp); + /* Decode TCP options, if any. */ + if (hlen > sizeof (e_tcphdr)) { + /* There's more than just the fixed-length header. Decode the + options. */ + optlen = hlen - sizeof (e_tcphdr); /* length of options, in bytes */ + tf = add_item_to_tree(tcp_tree, offset + 20, optlen, + "Options: (%d bytes)", optlen); + field_tree = gtk_tree_new(); + add_subtree(tf, field_tree, ETT_TCP_OPTIONS); + dissect_ip_tcp_options(field_tree, &pd[offset + 20], offset + 20, optlen, + tcpopts, N_TCP_OPTS, TCPOPT_EOL); + } } - /* Skip over header + options */ - offset += 4 * th.th_off; - /* until we decode those options, I'll check the packet length - to see if there's more data. -- gilbert */ - if (fd->cap_len > offset) { - switch(MIN(th.th_sport, th.th_dport)) { - case TCP_PORT_PRINTER: - dissect_lpd(pd, offset, fd, tree); - break; - default: - dissect_data(pd, offset, fd, 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 */ + if (fd->cap_len > offset) { + switch(MIN(th.th_sport, th.th_dport)) { + case TCP_PORT_PRINTER: + dissect_lpd(pd, offset, fd, tree); + break; + default: + dissect_data(pd, offset, fd, tree); + } + } - pi.srcport = th.th_sport; - pi.destport = th.th_dport; - - if( data_out_file ) { - reassemble_tcp( th.th_seq, /* sequence number */ - ( pi.iplen -( pi.iphdrlen * 4 )-( th.th_off * 4 ) ), /* length */ - ( pd+offset ), /* data */ - ( th.th_flags & 0x02 ), /* is syn set? */ - pi.ip_src ); /* src ip */ - } - - + pi.srcport = th.th_sport; + pi.destport = th.th_dport; + + if( data_out_file ) { + reassemble_tcp( th.th_seq, /* sequence number */ + ( pi.iplen -( pi.iphdrlen * 4 )-( th.th_off * 4 ) ), /* length */ + ( pd+offset ), /* data */ + ( th.th_flags & 0x02 ), /* is syn set? */ + pi.ip_src ); /* src ip */ + } } diff --git a/packet.h b/packet.h index 49f2dc880b..595774f9f3 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.12 1998/10/12 01:40:53 gerald Exp $ + * $Id: packet.h,v 1.13 1998/10/13 05:40:02 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -200,6 +200,12 @@ typedef struct _e_ip { guint32 ip_dst; } e_ip; +/* IP flags. */ +#define IP_CE 0x8000 /* Flag: "Congestion" */ +#define IP_DF 0x4000 /* Flag: "Don't Fragment" */ +#define IP_MF 0x2000 /* Flag: "More Fragments" */ +#define IP_OFFSET 0x1FFF /* "Fragment Offset" part */ + #define IPTOS_TOS_MASK 0x1E #define IPTOS_TOS(tos) ((tos) & IPTOS_TOS_MASK) #define IPTOS_NONE 0x00 @@ -208,6 +214,63 @@ typedef struct _e_ip { #define IPTOS_RELIABILITY 0x04 #define IPTOS_LOWCOST 0x02 +#define IPTOS_PREC_MASK 0xE0 +#define IPTOS_PREC(tos) ((tos)&IPTOS_PREC_MASK) +#define IPTOS_PREC_NETCONTROL 0xe0 +#define IPTOS_PREC_INTERNETCONTROL 0xc0 +#define IPTOS_PREC_CRITIC_ECP 0xa0 +#define IPTOS_PREC_FLASHOVERRIDE 0x80 +#define IPTOS_PREC_FLASH 0x60 +#define IPTOS_PREC_IMMEDIATE 0x40 +#define IPTOS_PREC_PRIORITY 0x20 +#define IPTOS_PREC_ROUTINE 0x00 + +/* IP options */ +#define IPOPT_COPY 0x80 + +#define IPOPT_CONTROL 0x00 +#define IPOPT_RESERVED1 0x20 +#define IPOPT_MEASUREMENT 0x40 +#define IPOPT_RESERVED2 0x60 + +#define IPOPT_END (0 |IPOPT_CONTROL) +#define IPOPT_NOOP (1 |IPOPT_CONTROL) +#define IPOPT_SEC (2 |IPOPT_CONTROL|IPOPT_COPY) +#define IPOPT_LSRR (3 |IPOPT_CONTROL|IPOPT_COPY) +#define IPOPT_TIMESTAMP (4 |IPOPT_MEASUREMENT) +#define IPOPT_RR (7 |IPOPT_CONTROL) +#define IPOPT_SID (8 |IPOPT_CONTROL|IPOPT_COPY) +#define IPOPT_SSRR (9 |IPOPT_CONTROL|IPOPT_COPY) +#define IPOPT_RA (20|IPOPT_CONTROL|IPOPT_COPY) + +/* IP option lengths */ +#define IPOLEN_SEC 11 +#define IPOLEN_LSRR_MIN 3 +#define IPOLEN_TIMESTAMP_MIN 5 +#define IPOLEN_RR_MIN 3 +#define IPOLEN_SID 4 +#define IPOLEN_SSRR_MIN 3 + +#define IPSEC_UNCLASSIFIED 0x0000 +#define IPSEC_CONFIDENTIAL 0xF135 +#define IPSEC_EFTO 0x789A +#define IPSEC_MMMM 0xBC4D +#define IPSEC_RESTRICTED 0xAF13 +#define IPSEC_SECRET 0xD788 +#define IPSEC_TOPSECRET 0x6BC5 +#define IPSEC_RESERVED1 0x35E2 +#define IPSEC_RESERVED2 0x9AF1 +#define IPSEC_RESERVED3 0x4D78 +#define IPSEC_RESERVED4 0x24BD +#define IPSEC_RESERVED5 0x135E +#define IPSEC_RESERVED6 0x89AF +#define IPSEC_RESERVED7 0xC4D6 +#define IPSEC_RESERVED8 0xE26B + +#define IPOPT_TS_TSONLY 0 /* timestamps only */ +#define IPOPT_TS_TSANDADDR 1 /* timestamps and addresses */ +#define IPOPT_TS_PRESPEC 3 /* specified modules only */ + #define IP_PROTO_ICMP 1 #define IP_PROTO_IGMP 2 #define IP_PROTO_TCP 6 @@ -256,6 +319,38 @@ typedef struct _e_tcphdr { guint16 th_urp; } e_tcphdr; +/* + * TCP option + */ + +#define TCPOPT_NOP 1 /* Padding */ +#define TCPOPT_EOL 0 /* End of options */ +#define TCPOPT_MSS 2 /* Segment size negotiating */ +#define TCPOPT_WINDOW 3 /* Window scaling */ +#define TCPOPT_SACK_PERM 4 /* SACK Permitted */ +#define TCPOPT_SACK 5 /* SACK Block */ +#define TCPOPT_ECHO 6 +#define TCPOPT_ECHOREPLY 7 +#define TCPOPT_TIMESTAMP 8 /* Better RTT estimations/PAWS */ +#define TCPOPT_CC 11 +#define TCPOPT_CCNEW 12 +#define TCPOPT_CCECHO 13 + +/* + * TCP option lengths + */ + +#define TCPOLEN_MSS 4 +#define TCPOLEN_WINDOW 3 +#define TCPOLEN_SACK_PERM 2 +#define TCPOLEN_SACK_MIN 2 +#define TCPOLEN_ECHO 6 +#define TCPOLEN_ECHOREPLY 6 +#define TCPOLEN_TIMESTAMP 10 +#define TCPOLEN_CC 6 +#define TCPOLEN_CCNEW 6 +#define TCPOLEN_CCECHO 6 + /* UDP structs and definitions */ typedef struct _e_udphdr { @@ -279,53 +374,59 @@ typedef struct _e_udphdr { /* Tree types. Each dissect_* routine should have one for each add_subtree() call. */ -#define ETT_FRAME 0 -#define ETT_IEEE8023 1 -#define ETT_ETHER2 2 -#define ETT_LLC 3 -#define ETT_TOKEN_RING 4 -#define ETT_TR_IERR_CNT 5 -#define ETT_TR_NERR_CNT 6 -#define ETT_TR_MAC 7 -#define ETT_PPP 8 -#define ETT_ARP 9 -#define ETT_IP 10 -#define ETT_UDP 11 -#define ETT_TCP 12 -#define ETT_ICMP 13 -#define ETT_IGMP 14 -#define ETT_IPX 15 -#define ETT_SPX 16 -#define ETT_NCP 17 -#define ETT_DNS 18 -#define ETT_DNS_ANS 19 -#define ETT_DNS_QRY 20 -#define ETT_RIP 21 -#define ETT_RIP_VEC 22 -#define ETT_OSPF 23 -#define ETT_OSPF_HDR 24 -#define ETT_OSPF_HELLO 25 -#define ETT_OSPF_DESC 26 -#define ETT_OSPF_LSR 27 -#define ETT_OSPF_LSA_UPD 28 -#define ETT_OSPF_LSA 29 -#define ETT_LPD 30 -#define ETT_RAW 31 -#define ETT_BOOTP 32 -#define ETT_BOOTP_OPTION 33 -#define ETT_IPv6 34 -#define ETT_CLNP 35 -#define ETT_COTP 36 -#define ETT_VINES 37 -#define ETT_VSPP 38 -#define ETT_IPXRIP 39 -#define ETT_IPXSAP 40 -#define ETT_IPXSAP_SERVER 41 -#define ETT_NULL 42 -#define ETT_FDDI 43 - -/* Should be the last item number plus one */ -#define NUM_TREE_TYPES 44 +enum { + ETT_FRAME, + ETT_IEEE8023, + ETT_ETHER2, + ETT_LLC, + ETT_TOKEN_RING, + ETT_TR_IERR_CNT, + ETT_TR_NERR_CNT, + ETT_TR_MAC, + ETT_PPP, + ETT_ARP, + ETT_FDDI, + ETT_NULL, + ETT_IP, + ETT_IP_OPTIONS, + ETT_IP_OPTION_SEC, + ETT_IP_OPTION_ROUTE, + ETT_IP_OPTION_TIMESTAMP, + ETT_UDP, + ETT_TCP, + ETT_TCP_OPTIONS, + ETT_TCP_OPTION_SACK, + ETT_ICMP, + ETT_IGMP, + ETT_IPX, + ETT_SPX, + ETT_NCP, + ETT_DNS, + ETT_DNS_ANS, + ETT_DNS_QRY, + ETT_RIP, + ETT_RIP_VEC, + ETT_OSPF, + ETT_OSPF_HDR, + ETT_OSPF_HELLO, + ETT_OSPF_DESC, + ETT_OSPF_LSR, + ETT_OSPF_LSA_UPD, + ETT_OSPF_LSA, + ETT_LPD, + ETT_RAW, + ETT_BOOTP, + ETT_BOOTP_OPTION, + ETT_IPv6, + ETT_CLNP, + ETT_COTP, + ETT_VINES, + ETT_VSPP, + ETT_IPXRIP, + ETT_IPXSAP, + ETT_IPXSAP_SERVER, + NUM_TREE_TYPES /* last item number plus one */ +}; /* The version of pcap.h that comes with some systems is missing these * #defines. @@ -343,6 +444,26 @@ typedef struct _e_udphdr { #define DLT_PPP_BSDOS 14 #endif +typedef enum { + NO_LENGTH, /* option has no data, hence no length */ + FIXED_LENGTH, /* option always has the same length */ + VARIABLE_LENGTH /* option is variable-length - optlen is minimum */ +} opt_len_type; + +/* Member of table of IP or TCP options. */ +typedef struct { + int optcode; /* code for option */ + char *name; /* name of option */ + opt_len_type len_type; /* type of option length field */ + int optlen; /* value length should be (minimum if VARIABLE) */ + void (*dissect)(GtkWidget *, const char *, const u_char *, int, guint); + /* routine to dissect option */ +} ip_tcp_opt; + +/* Routine to dissect IP or TCP options. */ +void dissect_ip_tcp_options(GtkWidget *, const u_char *, int, guint, + ip_tcp_opt *, int, int); + /* Utility routines used by packet*.c */ gchar* ether_to_str(guint8 *); gchar* ip_to_str(guint8 *);