Ethereal-dev: [ethereal-dev] IP(v4) and TCP option dissection
Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.
From: guy@xxxxxxxxxx (Guy Harris)
Date: Mon, 12 Oct 1998 22:44:35 -0700 (PDT)
I just checked in some changes to add IP and TCP option dissecting, and make some other changes. As indicated, it probably won't take too much work to use it for IPv6 options as well. Add a routine to dissect IP or TCP options (and, from a look at RFC 1883, it should, perhaps with some additions, be able to handle IPv6 options as well). Make the IPv4 and TCP dissectors use it. Fix a typo in the IP dissector ("Unknon" for "Unknown"). Show the IP and TCP header lengths as byte counts rather than 4-byte-word counts. Show the protocol field value of an IP header as a name if it's a protocol we know about. List the acknowledgment and urgent pointer values in a TCP header only if the corresponding flag is set. Make the ETT_ values members of an enum, so that the compiler automatically assigns them sequential integer values (at least if said compiler conforms to the ANSI C standard). The patch is: Index: packet.h =================================================================== RCS file: /usr/local/cvsroot/ethereal/packet.h,v retrieving revision 1.12 diff -c -r1.12 packet.h *** packet.h 1998/10/12 01:40:53 1.12 --- packet.h 1998/10/13 05:39:14 *************** *** 200,205 **** --- 200,211 ---- 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,213 **** --- 214,276 ---- #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,261 **** --- 319,356 ---- 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,331 **** /* 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 /* The version of pcap.h that comes with some systems is missing these * #defines. --- 374,432 ---- /* Tree types. Each dissect_* routine should have one for each add_subtree() call. */ ! 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. *************** *** 342,347 **** --- 443,468 ---- #ifndef DLT_PPP_BSDOS #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 *); Index: packet-ip.c =================================================================== RCS file: /usr/local/cvsroot/ethereal/packet-ip.c,v retrieving revision 1.6 diff -c -r1.6 packet-ip.c *** packet-ip.c 1998/10/10 18:23:42 1.6 --- packet-ip.c 1998/10/13 05:39:15 *************** *** 47,57 **** extern packet_info pi; void dissect_ip(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) { e_ip iph; ! GtkWidget *ip_tree, *ti; gchar tos_str[32]; /* To do: check for runts, errs, etc. */ /* Avoids alignment problems on many architectures. */ --- 47,410 ---- 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, *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,65 **** --- 413,420 ---- 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,113 **** strcpy(tos_str, "Minimize cost"); break; default: ! strcpy(tos_str, "Unknon. Malformed?"); break; } if (tree) { ! ti = add_item_to_tree(GTK_WIDGET(tree), offset, (iph.ip_hl * 4), ! "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, 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); --- 452,467 ---- strcpy(tos_str, "Minimize cost"); break; default: ! strcpy(tos_str, "Unknown. Malformed?"); break; } if (tree) { ! 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 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,131 **** iph.ip_id); /* To do: add flags */ add_item_to_tree(ip_tree, offset + 6, 2, "Fragment offset: %d", ! iph.ip_off & 0x1fff); 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); 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)); } pi.srcip = ip_to_str( (guint8 *) &iph.ip_src); --- 469,501 ---- iph.ip_id); /* To do: add flags */ add_item_to_tree(ip_tree, offset + 6, 2, "Fragment offset: %d", ! iph.ip_off & IP_OFFSET); add_item_to_tree(ip_tree, offset + 8, 1, "Time to live: %d", iph.ip_ttl); ! 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,141 **** pi.iphdrlen = iph.ip_hl; pi.ip_src = iph.ip_src; ! offset += iph.ip_hl * 4; switch (iph.ip_p) { case IP_PROTO_ICMP: dissect_icmp(pd, offset, fd, tree); --- 505,511 ---- pi.iphdrlen = iph.ip_hl; pi.ip_src = iph.ip_src; ! offset += hlen; switch (iph.ip_p) { case IP_PROTO_ICMP: dissect_icmp(pd, offset, fd, tree); Index: packet-tcp.c =================================================================== RCS file: /usr/local/cvsroot/ethereal/packet-tcp.c,v retrieving revision 1.4 diff -c -r1.4 packet-tcp.c *** packet-tcp.c 1998/09/27 22:12:38 1.4 --- packet-tcp.c 1998/10/13 05:39:15 *************** *** 46,59 **** extern FILE* data_out_file; extern packet_info pi; void dissect_tcp(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) { e_tcphdr th; ! GtkWidget *tcp_tree, *ti; gchar flags[64] = "<None>"; gchar *fstr[] = {"FIN", "SYN", "RST", "PSH", "ACK", "URG"}; gint fpos = 0, i; guint bpos; /* To do: Check for {cap len,pkt len} < struct len */ /* Avoids alignment problems on many architectures. */ --- 46,230 ---- 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, *field_tree, *tf; gchar flags[64] = "<None>"; 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,135 **** th.th_sport, th.th_dport); } if (tree) { ! ti = add_item_to_tree(GTK_WIDGET(tree), offset, 20, "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", 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); 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 */ ! ! } ! /* 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); ! } ! } ! ! 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 */ ! } } --- 256,320 ---- 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, 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: %u", th.th_seq); ! 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); ! 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 += 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 */ + } }
- Prev by Date: [ethereal-dev] Patch to "packet-arp.c" checked in
- Next by Date: [ethereal-dev] Second patch to "packet-fddi.c"
- Previous by thread: Re: [ethereal-dev] Patch to "packet-fddi.c" + another question
- Next by thread: [ethereal-dev] Second patch to "packet-fddi.c"
- Index(es):