2 * Routines for TCP packet disassembly
4 * $Id: packet-tcp.c,v 1.57 2000/02/15 21:03:15 gram Exp $
6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@zing.org>
8 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30 #ifdef HAVE_SYS_TYPES_H
31 # include <sys/types.h>
34 #ifdef HAVE_NETINET_IN_H
35 # include <netinet/in.h>
44 #ifdef NEED_SNPRINTF_H
50 # include "snprintf.h"
55 #include "packet-bgp.h"
56 #include "packet-ip.h"
57 #include "packet-ftp.h"
58 #include "packet-giop.h"
59 #include "packet-http.h"
60 #include "packet-imap.h"
61 #include "packet-irc.h"
62 #include "packet-ldap.h"
63 #include "packet-lpd.h"
64 #include "packet-mapi.h"
65 #include "packet-nbns.h"
66 #include "packet-ncp.h"
67 #include "packet-nntp.h"
68 #include "packet-ntp.h"
69 #include "packet-pop.h"
70 #include "packet-pptp.h"
71 #include "packet-rpc.h"
72 #include "packet-rtsp.h"
73 #include "packet-srvloc.h"
74 #include "packet-tacacs.h"
75 #include "packet-telnet.h"
76 #include "packet-tns.h"
77 #include "packet-yhoo.h"
79 extern FILE* data_out_file;
81 static gchar info_str[COL_MAX_LEN];
84 static int proto_tcp = -1;
85 static int hf_tcp_srcport = -1;
86 static int hf_tcp_dstport = -1;
87 static int hf_tcp_port = -1;
88 static int hf_tcp_seq = -1;
89 static int hf_tcp_ack = -1;
90 static int hf_tcp_hdr_len = -1;
91 static int hf_tcp_flags = -1;
92 static int hf_tcp_flags_urg = -1;
93 static int hf_tcp_flags_ack = -1;
94 static int hf_tcp_flags_push = -1;
95 static int hf_tcp_flags_reset = -1;
96 static int hf_tcp_flags_syn = -1;
97 static int hf_tcp_flags_fin = -1;
98 static int hf_tcp_window_size = -1;
99 static int hf_tcp_checksum = -1;
100 static int hf_tcp_urgent_pointer = -1;
102 static gint ett_tcp = -1;
103 static gint ett_tcp_flags = -1;
104 static gint ett_tcp_options = -1;
105 static gint ett_tcp_option_sack = -1;
109 #define TCP_PORT_FTPDATA 20
110 #define TCP_PORT_FTP 21
111 #define TCP_PORT_TELNET 23
112 #define TCP_PORT_SMTP 25
113 #define TCP_PORT_HTTP 80
114 #define TCP_PORT_TACACS 49
115 #define TCP_PORT_POP 110
116 #define TCP_PORT_NNTP 119
117 #define TCP_PORT_NTP 123
118 #define TCP_PORT_NBSS 139
119 #define TCP_PORT_IMAP 143
120 #define TCP_PORT_BGP 179
121 #define TCP_PORT_LDAP 389
122 #define TCP_PORT_SRVLOC 427
123 #define TCP_PORT_PRINTER 515
124 #define TCP_PORT_NCP 524
125 #define TCP_PORT_RTSP 554
126 #define TCP_PORT_MAPI 1065
127 #define TCP_PORT_TNS 1521
128 #define TCP_PORT_PPTP 1723
129 #define TCP_PORT_PROXY_HTTP 3128
130 #define TCP_PORT_PROXY_ADMIN_HTTP 3132
131 #define TCP_PORT_YHOO 5050
132 #define TCP_ALT_PORT_HTTP 8080
133 #define TCP_PORT_IRC 6667
134 /* good candidate for dynamic port specification */
136 /* TCP structs and definitions */
138 typedef struct _e_tcphdr {
143 guint8 th_off_x2; /* combines th_off and th_x2 */
160 #define TCPOPT_NOP 1 /* Padding */
161 #define TCPOPT_EOL 0 /* End of options */
162 #define TCPOPT_MSS 2 /* Segment size negotiating */
163 #define TCPOPT_WINDOW 3 /* Window scaling */
164 #define TCPOPT_SACK_PERM 4 /* SACK Permitted */
165 #define TCPOPT_SACK 5 /* SACK Block */
166 #define TCPOPT_ECHO 6
167 #define TCPOPT_ECHOREPLY 7
168 #define TCPOPT_TIMESTAMP 8 /* Better RTT estimations/PAWS */
170 #define TCPOPT_CCNEW 12
171 #define TCPOPT_CCECHO 13
177 #define TCPOLEN_MSS 4
178 #define TCPOLEN_WINDOW 3
179 #define TCPOLEN_SACK_PERM 2
180 #define TCPOLEN_SACK_MIN 2
181 #define TCPOLEN_ECHO 6
182 #define TCPOLEN_ECHOREPLY 6
183 #define TCPOLEN_TIMESTAMP 10
185 #define TCPOLEN_CCNEW 6
186 #define TCPOLEN_CCECHO 6
189 tcp_info_append_uint(const char *abbrev, guint32 val) {
194 add_len = snprintf(&info_str[info_len], COL_MAX_LEN - info_len, " %s=%u",
201 dissect_tcpopt_maxseg(const ip_tcp_opt *optp, const u_char *opd,
202 int offset, guint optlen, proto_tree *opt_tree)
204 proto_tree_add_text(opt_tree, offset, optlen,
205 "%s: %u bytes", optp->name, pntohs(opd));
206 tcp_info_append_uint("MSS", pntohs(opd));
210 dissect_tcpopt_wscale(const ip_tcp_opt *optp, const u_char *opd,
211 int offset, guint optlen, proto_tree *opt_tree)
213 proto_tree_add_text(opt_tree, offset, optlen,
214 "%s: %u bytes", optp->name, *opd);
215 tcp_info_append_uint("WS", *opd);
219 dissect_tcpopt_sack(const ip_tcp_opt *optp, const u_char *opd,
220 int offset, guint optlen, proto_tree *opt_tree)
222 proto_tree *field_tree = NULL;
224 guint leftedge, rightedge;
226 tf = proto_tree_add_text(opt_tree, offset, optlen, "%s:", optp->name);
227 offset += 2; /* skip past type and length */
228 optlen -= 2; /* subtract size of type and length */
230 if (field_tree == NULL) {
231 /* Haven't yet made a subtree out of this option. Do so. */
232 field_tree = proto_item_add_subtree(tf, *optp->subtree_index);
235 proto_tree_add_text(field_tree, offset, optlen,
236 "(suboption would go past end of option)");
239 /* XXX - check whether it goes past end of packet */
240 leftedge = pntohl(opd);
244 proto_tree_add_text(field_tree, offset, optlen,
245 "(suboption would go past end of option)");
248 /* XXX - check whether it goes past end of packet */
249 rightedge = pntohl(opd);
252 proto_tree_add_text(field_tree, offset, 8,
253 "left edge = %u, right edge = %u", leftedge, rightedge);
254 tcp_info_append_uint("SLE", leftedge);
255 tcp_info_append_uint("SRE", rightedge);
261 dissect_tcpopt_echo(const ip_tcp_opt *optp, const u_char *opd,
262 int offset, guint optlen, proto_tree *opt_tree)
264 proto_tree_add_text(opt_tree, offset, optlen,
265 "%s: %u", optp->name, pntohl(opd));
266 tcp_info_append_uint("ECHO", pntohl(opd));
270 dissect_tcpopt_timestamp(const ip_tcp_opt *optp, const u_char *opd,
271 int offset, guint optlen, proto_tree *opt_tree)
273 proto_tree_add_text(opt_tree, offset, optlen,
274 "%s: tsval %u, tsecr %u", optp->name, pntohl(opd), pntohl(opd + 4));
275 tcp_info_append_uint("TSV", pntohl(opd));
276 tcp_info_append_uint("TSER", pntohl(opd + 4));
280 dissect_tcpopt_cc(const ip_tcp_opt *optp, const u_char *opd,
281 int offset, guint optlen, proto_tree *opt_tree)
283 proto_tree_add_text(opt_tree, offset, optlen,
284 "%s: %u", optp->name, pntohl(opd));
285 tcp_info_append_uint("CC", pntohl(opd));
288 static const ip_tcp_opt tcpopts[] = {
307 "Maximum segment size",
311 dissect_tcpopt_maxseg
319 dissect_tcpopt_wscale
332 &ett_tcp_option_sack,
359 dissect_tcpopt_timestamp
387 #define N_TCP_OPTS (sizeof tcpopts / sizeof tcpopts[0])
390 static const true_false_string flags_set_truth = {
396 dissect_tcp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
398 proto_tree *tcp_tree = NULL, *field_tree = NULL;
400 gchar flags[64] = "<None>";
401 gchar *fstr[] = {"FIN", "SYN", "RST", "PSH", "ACK", "URG"};
406 guint packet_max = pi.len;
408 /* To do: Check for {cap len,pkt len} < struct len */
409 /* Avoids alignment problems on many architectures. */
410 memcpy(&th, &pd[offset], sizeof(e_tcphdr));
411 th.th_sport = ntohs(th.th_sport);
412 th.th_dport = ntohs(th.th_dport);
413 th.th_win = ntohs(th.th_win);
414 th.th_sum = ntohs(th.th_sum);
415 th.th_urp = ntohs(th.th_urp);
416 th.th_seq = ntohl(th.th_seq);
417 th.th_ack = ntohl(th.th_ack);
421 if (check_col(fd, COL_PROTOCOL) || tree) {
422 for (i = 0; i < 6; i++) {
424 if (th.th_flags & bpos) {
426 strcpy(&flags[fpos], ", ");
429 strcpy(&flags[fpos], fstr[i]);
436 hlen = hi_nibble(th.th_off_x2) * 4; /* TCP header length, in bytes */
438 if (check_col(fd, COL_PROTOCOL))
439 col_add_str(fd, COL_PROTOCOL, "TCP");
440 if (check_col(fd, COL_INFO)) {
441 /* Copy the data into info_str in case one of the option handling
442 routines needs to append to it. */
443 if (th.th_flags & TH_URG)
444 info_len = snprintf(info_str, COL_MAX_LEN, "%s > %s [%s] Seq=%u Ack=%u Win=%u Urg=%u",
445 get_tcp_port(th.th_sport), get_tcp_port(th.th_dport), flags,
446 th.th_seq, th.th_ack, th.th_win, th.th_urp);
448 info_len = snprintf(info_str, COL_MAX_LEN, "%s > %s [%s] Seq=%u Ack=%u Win=%u",
449 get_tcp_port(th.th_sport), get_tcp_port(th.th_dport), flags,
450 th.th_seq, th.th_ack, th.th_win);
451 /* The info column is actually written after the options are decoded */
455 ti = proto_tree_add_item_format(tree, proto_tcp, offset, hlen, NULL, "Transmission Control Protocol, Src Port: %s (%u), Dst Port: %s (%u), Seq: %u, Ack: %u", get_tcp_port(th.th_sport), th.th_sport, get_tcp_port(th.th_dport), th.th_dport, th.th_seq, th.th_ack);
456 tcp_tree = proto_item_add_subtree(ti, ett_tcp);
457 proto_tree_add_item_format(tcp_tree, hf_tcp_srcport, offset, 2, th.th_sport,
458 "Source port: %s (%u)", get_tcp_port(th.th_sport), th.th_sport);
459 proto_tree_add_item_format(tcp_tree, hf_tcp_dstport, offset + 2, 2, th.th_dport,
460 "Destination port: %s (%u)", get_tcp_port(th.th_dport), th.th_dport);
461 proto_tree_add_item_hidden(tcp_tree, hf_tcp_port, offset, 2, th.th_sport);
462 proto_tree_add_item_hidden(tcp_tree, hf_tcp_port, offset + 2, 2, th.th_dport);
463 proto_tree_add_item(tcp_tree, hf_tcp_seq, offset + 4, 4, th.th_seq);
464 if (th.th_flags & TH_ACK)
465 proto_tree_add_item(tcp_tree, hf_tcp_ack, offset + 8, 4, th.th_ack);
466 proto_tree_add_item_format(tcp_tree, hf_tcp_hdr_len, offset + 12, 1, hlen,
467 "Header length: %u bytes", hlen);
468 tf = proto_tree_add_item_format(tcp_tree, hf_tcp_flags, offset + 13, 1,
469 th.th_flags, "Flags: 0x%04x (%s)", th.th_flags, flags);
470 field_tree = proto_item_add_subtree(tf, ett_tcp_flags);
471 proto_tree_add_item(field_tree, hf_tcp_flags_urg, offset + 13, 1, th.th_flags);
472 proto_tree_add_item(field_tree, hf_tcp_flags_ack, offset + 13, 1, th.th_flags);
473 proto_tree_add_item(field_tree, hf_tcp_flags_push, offset + 13, 1, th.th_flags);
474 proto_tree_add_item(field_tree, hf_tcp_flags_reset, offset + 13, 1, th.th_flags);
475 proto_tree_add_item(field_tree, hf_tcp_flags_syn, offset + 13, 1, th.th_flags);
476 proto_tree_add_item(field_tree, hf_tcp_flags_fin, offset + 13, 1, th.th_flags);
477 proto_tree_add_item(tcp_tree, hf_tcp_window_size, offset + 14, 2, th.th_win);
478 proto_tree_add_item(tcp_tree, hf_tcp_checksum, offset + 16, 2, th.th_sum);
479 if (th.th_flags & TH_URG)
480 proto_tree_add_item(tcp_tree, hf_tcp_urgent_pointer, offset + 18, 2, th.th_urp);
483 /* Decode TCP options, if any. */
484 if (tree && hlen > sizeof (e_tcphdr)) {
485 /* There's more than just the fixed-length header. Decode the
487 optlen = hlen - sizeof (e_tcphdr); /* length of options, in bytes */
488 tf = proto_tree_add_text(tcp_tree, offset + 20, optlen,
489 "Options: (%d bytes)", optlen);
490 field_tree = proto_item_add_subtree(tf, ett_tcp_options);
491 dissect_ip_tcp_options(&pd[offset + 20], offset + 20, optlen,
492 tcpopts, N_TCP_OPTS, TCPOPT_EOL, field_tree);
495 if (check_col(fd, COL_INFO))
496 col_add_str(fd, COL_INFO, info_str);
498 /* Skip over header + options */
502 pi.srcport = th.th_sport;
503 pi.destport = th.th_dport;
505 /* Check the packet length to see if there's more data
506 (it could be an ACK-only packet) */
507 if (packet_max > offset) {
509 /* try to apply the plugins */
511 plugin *pt_plug = plugin_list;
515 if (pt_plug->enabled && !strcmp(pt_plug->protocol, "tcp") &&
516 tree && dfilter_apply(pt_plug->filter, tree, pd)) {
517 pt_plug->dissector(pd, offset, fd, tree);
520 pt_plug = pt_plug->next;
525 /* ONC RPC. We can't base this on anything in the TCP header; we have
526 to look at the payload. If "dissect_rpc()" returns TRUE, it was
527 an RPC packet, otherwise it's some other type of packet. */
528 if (dissect_rpc(pd, offset, fd, tree))
531 /* XXX - this should be handled the way UDP handles this, with a table
532 of port numbers to which stuff can be added */
533 #define PORT_IS(port) (th.th_sport == port || th.th_dport == port)
534 if (PORT_IS(TCP_PORT_PRINTER))
535 dissect_lpd(pd, offset, fd, tree);
536 else if (PORT_IS(TCP_PORT_TELNET)) {
537 pi.match_port = TCP_PORT_TELNET;
538 dissect_telnet(pd, offset, fd, tree);
539 } else if (PORT_IS(TCP_PORT_FTPDATA)) {
540 pi.match_port = TCP_PORT_FTPDATA;
541 dissect_ftpdata(pd, offset, fd, tree);
542 } else if (PORT_IS(TCP_PORT_FTP)) {
543 pi.match_port = TCP_PORT_FTP;
544 dissect_ftp(pd, offset, fd, tree);
545 } else if (PORT_IS(TCP_PORT_POP)) {
546 pi.match_port = TCP_PORT_POP;
547 dissect_pop(pd, offset, fd, tree);
548 } else if (PORT_IS(TCP_PORT_IMAP)) {
549 pi.match_port = TCP_PORT_IMAP;
550 dissect_imap(pd, offset, fd, tree);
551 } else if (PORT_IS(TCP_PORT_NNTP)) {
552 pi.match_port = TCP_PORT_NNTP;
553 dissect_nntp(pd, offset, fd, tree);
554 } else if (PORT_IS(TCP_PORT_NTP)) {
555 pi.match_port = TCP_PORT_NTP;
556 dissect_ntp(pd, offset, fd, tree);
557 } else if (PORT_IS(TCP_PORT_PPTP)) {
558 pi.match_port = TCP_PORT_PPTP;
559 dissect_pptp(pd, offset, fd, tree);
560 } else if (PORT_IS(TCP_PORT_HTTP) || PORT_IS(TCP_ALT_PORT_HTTP)
561 || PORT_IS(631) || PORT_IS(TCP_PORT_PROXY_HTTP)
562 || PORT_IS(TCP_PORT_PROXY_ADMIN_HTTP))
563 dissect_http(pd, offset, fd, tree);
564 else if (PORT_IS(TCP_PORT_NBSS)) {
565 pi.match_port = TCP_PORT_NBSS;
566 dissect_nbss(pd, offset, fd, tree);
567 } else if (PORT_IS(TCP_PORT_RTSP))
568 dissect_rtsp(pd, offset, fd, tree);
569 else if (PORT_IS(TCP_PORT_BGP)) {
570 pi.match_port = TCP_PORT_BGP;
571 dissect_bgp(pd, offset, fd, tree);
572 } else if (PORT_IS(TCP_PORT_TACACS)) {
573 pi.match_port = TCP_PORT_TACACS;
574 dissect_tacplus(pd, offset, fd, tree);
575 } else if (PORT_IS(TCP_PORT_MAPI)) {
576 pi.match_port = TCP_PORT_MAPI;
577 dissect_mapi(pd, offset, fd, tree);
578 } else if (PORT_IS(TCP_PORT_TNS)) {
579 pi.match_port = TCP_PORT_TNS;
580 dissect_tns(pd, offset, fd, tree);
581 } else if (PORT_IS(TCP_PORT_IRC)) {
582 pi.match_port = TCP_PORT_IRC;
583 dissect_irc(pd, offset, fd, tree);
584 } else if (PORT_IS(TCP_PORT_LDAP)) {
585 pi.match_port = TCP_PORT_LDAP;
586 dissect_ldap(pd, offset, fd, tree);
587 } else if (PORT_IS(TCP_PORT_SRVLOC)) {
588 pi.match_port = TCP_PORT_SRVLOC;
589 dissect_srvloc(pd, offset, fd, tree);
590 } else if (PORT_IS(TCP_PORT_NCP)) {
591 pi.match_port = TCP_PORT_NCP;
592 dissect_ncp(pd, offset, fd, tree); /* XXX -- need to handle nw_server_address */
594 /* check existence of high level protocols */
596 if (memcmp(&pd[offset], "GIOP", 4) == 0) {
597 dissect_giop(pd, offset, fd, tree);
599 else if ( PORT_IS(TCP_PORT_YHOO) &&
600 (memcmp(&pd[offset], "YPNS", 4) == 0 ||
601 memcmp(&pd[offset], "YHOO", 4) == 0 )) {
602 dissect_yhoo(pd, offset, fd, tree);
605 dissect_data(pd, offset, fd, tree);
612 if( data_out_file ) {
613 reassemble_tcp( th.th_seq, /* sequence number */
614 ( pi.len - offset ), /* data length */
615 ( pd+offset ), /* data */
616 ( pi.captured_len - offset ), /* captured data length */
617 ( th.th_flags & TH_SYN ), /* is syn set? */
628 proto_register_tcp(void)
630 static hf_register_info hf[] = {
633 { "Source Port", "tcp.srcport", FT_UINT16, BASE_DEC, NULL, 0x0,
637 { "Destination Port", "tcp.dstport", FT_UINT16, BASE_DEC, NULL, 0x0,
641 { "Source or Destination Port", "tcp.port", FT_UINT16, BASE_DEC, NULL, 0x0,
645 { "Sequence number", "tcp.seq", FT_UINT32, BASE_DEC, NULL, 0x0,
649 { "Acknowledgement number", "tcp.ack", FT_UINT32, BASE_DEC, NULL, 0x0,
653 { "Header Length", "tcp.hdr_len", FT_UINT8, BASE_DEC, NULL, 0x0,
657 { "Flags", "tcp.flags", FT_UINT8, BASE_HEX, NULL, 0x0,
661 { "Urgent", "tcp.flags.urg", FT_BOOLEAN, 8, TFS(&flags_set_truth), TH_URG,
665 { "Acknowledgment", "tcp.flags.ack", FT_BOOLEAN, 8, TFS(&flags_set_truth), TH_ACK,
668 { &hf_tcp_flags_push,
669 { "Push", "tcp.flags.push", FT_BOOLEAN, 8, TFS(&flags_set_truth), TH_PUSH,
672 { &hf_tcp_flags_reset,
673 { "Reset", "tcp.flags.reset", FT_BOOLEAN, 8, TFS(&flags_set_truth), TH_RST,
677 { "Syn", "tcp.flags.syn", FT_BOOLEAN, 8, TFS(&flags_set_truth), TH_SYN,
681 { "Fin", "tcp.flags.fin", FT_BOOLEAN, 8, TFS(&flags_set_truth), TH_FIN,
684 { &hf_tcp_window_size,
685 { "Window size", "tcp.window_size", FT_UINT16, BASE_DEC, NULL, 0x0,
689 { "Checksum", "tcp.checksum", FT_UINT16, BASE_HEX, NULL, 0x0,
692 { &hf_tcp_urgent_pointer,
693 { "Urgent pointer", "tcp.urgent_pointer", FT_UINT16, BASE_DEC, NULL, 0x0,
696 static gint *ett[] = {
700 &ett_tcp_option_sack,
703 proto_tcp = proto_register_protocol ("Transmission Control Protocol", "tcp");
704 proto_register_field_array(proto_tcp, hf, array_length(hf));
705 proto_register_subtree_array(ett, array_length(ett));