2 * Routines for TCP packet disassembly
4 * $Id: packet-tcp.c,v 1.26 1999/07/07 22:51:55 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>
45 #ifdef NEED_SNPRINTF_H
51 # include "snprintf.h"
54 #ifndef __PACKET_IP_H__
55 #include "packet-ip.h"
58 extern FILE* data_out_file;
59 extern packet_info pi;
61 static gchar info_str[COL_MAX_LEN];
66 #define TCP_PORT_FTPDATA 20
67 #define TCP_PORT_FTP 21
68 #define TCP_PORT_TELNET 23
69 #define TCP_PORT_SMTP 25
70 #define TCP_PORT_HTTP 80
71 #define TCP_PORT_POP 110
72 #define TCP_PORT_NNTP 119
73 #define TCP_PORT_NBSS 139
74 #define TCP_PORT_PRINTER 515
75 #define TCP_ALT_PORT_HTTP 8080
76 #define TCP_PORT_PPTP 1723
77 #define TCP_PORT_RTSP 554
79 /* TCP structs and definitions */
81 typedef struct _e_tcphdr {
86 guint8 th_off_x2; /* combines th_off and th_x2 */
103 #define TCPOPT_NOP 1 /* Padding */
104 #define TCPOPT_EOL 0 /* End of options */
105 #define TCPOPT_MSS 2 /* Segment size negotiating */
106 #define TCPOPT_WINDOW 3 /* Window scaling */
107 #define TCPOPT_SACK_PERM 4 /* SACK Permitted */
108 #define TCPOPT_SACK 5 /* SACK Block */
109 #define TCPOPT_ECHO 6
110 #define TCPOPT_ECHOREPLY 7
111 #define TCPOPT_TIMESTAMP 8 /* Better RTT estimations/PAWS */
113 #define TCPOPT_CCNEW 12
114 #define TCPOPT_CCECHO 13
120 #define TCPOLEN_MSS 4
121 #define TCPOLEN_WINDOW 3
122 #define TCPOLEN_SACK_PERM 2
123 #define TCPOLEN_SACK_MIN 2
124 #define TCPOLEN_ECHO 6
125 #define TCPOLEN_ECHOREPLY 6
126 #define TCPOLEN_TIMESTAMP 10
128 #define TCPOLEN_CCNEW 6
129 #define TCPOLEN_CCECHO 6
132 tcp_info_append_uint(const char *abbrev, guint32 val) {
137 add_len = snprintf(&info_str[info_len], COL_MAX_LEN - info_len, " %s=%u",
144 dissect_tcpopt_maxseg(proto_tree *opt_tree, const char *name, const u_char *opd,
145 int offset, guint optlen)
147 proto_tree_add_text(opt_tree, offset, optlen,
148 "%s: %u bytes", name, pntohs(opd));
149 tcp_info_append_uint("MSS", pntohs(opd));
153 dissect_tcpopt_wscale(proto_tree *opt_tree, const char *name, const u_char *opd,
154 int offset, guint optlen)
156 proto_tree_add_text(opt_tree, offset, optlen,
157 "%s: %u bytes", name, *opd);
158 tcp_info_append_uint("WS", *opd);
162 dissect_tcpopt_sack(proto_tree *opt_tree, const char *name, const u_char *opd,
163 int offset, guint optlen)
165 proto_tree *field_tree = NULL;
167 guint leftedge, rightedge;
169 tf = proto_tree_add_text(opt_tree, offset, optlen, "%s:", name);
170 offset += 2; /* skip past type and length */
171 optlen -= 2; /* subtract size of type and length */
173 if (field_tree == NULL) {
174 /* Haven't yet made a subtree out of this option. Do so. */
175 field_tree = proto_item_add_subtree(tf, ETT_TCP_OPTION_SACK);
178 proto_tree_add_text(field_tree, offset, optlen,
179 "(suboption would go past end of option)");
182 /* XXX - check whether it goes past end of packet */
183 leftedge = pntohl(opd);
187 proto_tree_add_text(field_tree, offset, optlen,
188 "(suboption would go past end of option)");
191 /* XXX - check whether it goes past end of packet */
192 rightedge = pntohl(opd);
195 proto_tree_add_text(field_tree, offset, 8,
196 "left edge = %u, right edge = %u", leftedge, rightedge);
197 tcp_info_append_uint("SLE", leftedge);
198 tcp_info_append_uint("SRE", rightedge);
204 dissect_tcpopt_echo(proto_tree *opt_tree, const char *name, const u_char *opd,
205 int offset, guint optlen)
207 proto_tree_add_text(opt_tree, offset, optlen,
208 "%s: %u", name, pntohl(opd));
209 tcp_info_append_uint("ECHO", pntohl(opd));
213 dissect_tcpopt_timestamp(proto_tree *opt_tree, const char *name,
214 const u_char *opd, int offset, guint optlen)
216 proto_tree_add_text(opt_tree, offset, optlen,
217 "%s: tsval %u, tsecr %u", name, pntohl(opd), pntohl(opd + 4));
218 tcp_info_append_uint("TSV", pntohl(opd));
219 tcp_info_append_uint("TSER", pntohl(opd + 4));
223 dissect_tcpopt_cc(proto_tree *opt_tree, const char *name, const u_char *opd,
224 int offset, guint optlen)
226 proto_tree_add_text(opt_tree, offset, optlen,
227 "%s: %u", name, pntohl(opd));
228 tcp_info_append_uint("CC", pntohl(opd));
231 static ip_tcp_opt tcpopts[] = {
248 "Maximum segment size",
251 dissect_tcpopt_maxseg
258 dissect_tcpopt_wscale
293 dissect_tcpopt_timestamp
318 #define N_TCP_OPTS (sizeof tcpopts / sizeof tcpopts[0])
321 dissect_tcp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
323 proto_tree *tcp_tree = NULL, *field_tree = NULL;
325 gchar flags[64] = "<None>";
326 gchar *fstr[] = {"FIN", "SYN", "RST", "PSH", "ACK", "URG"};
331 guint packet_max = pi.payload + offset;
334 /* To do: Check for {cap len,pkt len} < struct len */
335 /* Avoids alignment problems on many architectures. */
336 memcpy(&th, &pd[offset], sizeof(e_tcphdr));
337 th.th_sport = ntohs(th.th_sport);
338 th.th_dport = ntohs(th.th_dport);
339 th.th_win = ntohs(th.th_win);
340 th.th_sum = ntohs(th.th_sum);
341 th.th_urp = ntohs(th.th_urp);
342 th.th_seq = ntohl(th.th_seq);
343 th.th_ack = ntohl(th.th_ack);
347 if (check_col(fd, COL_PROTOCOL) || tree) {
348 for (i = 0; i < 6; i++) {
350 if (th.th_flags & bpos) {
352 strcpy(&flags[fpos], ", ");
355 strcpy(&flags[fpos], fstr[i]);
362 hlen = hi_nibble(th.th_off_x2) * 4; /* TCP header length, in bytes */
364 payload = pi.payload - hlen;
366 if (check_col(fd, COL_RES_SRC_PORT))
367 col_add_str(fd, COL_RES_SRC_PORT, get_tcp_port(th.th_sport));
368 if (check_col(fd, COL_UNRES_SRC_PORT))
369 col_add_fstr(fd, COL_UNRES_SRC_PORT, "%u", th.th_sport);
370 if (check_col(fd, COL_RES_DST_PORT))
371 col_add_str(fd, COL_RES_DST_PORT, get_tcp_port(th.th_dport));
372 if (check_col(fd, COL_UNRES_DST_PORT))
373 col_add_fstr(fd, COL_UNRES_DST_PORT, "%u", th.th_dport);
374 if (check_col(fd, COL_PROTOCOL))
375 col_add_str(fd, COL_PROTOCOL, "TCP");
376 if (check_col(fd, COL_INFO)) {
377 /* Copy the data into info_str in case one of the option handling
378 routines needs to append to it. */
379 if (th.th_flags & TH_URG)
380 info_len = snprintf(info_str, COL_MAX_LEN, "%s > %s [%s] Seq=%u Ack=%u Win=%u Urg=%u",
381 get_tcp_port(th.th_sport), get_tcp_port(th.th_dport), flags,
382 th.th_seq, th.th_ack, th.th_win, th.th_urp);
384 info_len = snprintf(info_str, COL_MAX_LEN, "%s > %s [%s] Seq=%u Ack=%u Win=%u",
385 get_tcp_port(th.th_sport), get_tcp_port(th.th_dport), flags,
386 th.th_seq, th.th_ack, th.th_win);
387 /* The info column is actually written after the options are decoded */
391 ti = proto_tree_add_text(tree, offset, hlen,
392 "Transmission Control Protocol");
393 tcp_tree = proto_item_add_subtree(ti, ETT_TCP);
394 proto_tree_add_text(tcp_tree, offset, 2, "Source port: %s (%u)",
395 get_tcp_port(th.th_sport), th.th_sport);
396 proto_tree_add_text(tcp_tree, offset + 2, 2, "Destination port: %s (%u)",
397 get_tcp_port(th.th_dport), th.th_dport);
398 proto_tree_add_text(tcp_tree, offset + 4, 4, "Sequence number: %u",
400 if (th.th_flags & TH_ACK)
401 proto_tree_add_text(tcp_tree, offset + 8, 4, "Acknowledgement number: %u",
403 proto_tree_add_text(tcp_tree, offset + 12, 1, "Header length: %u bytes", hlen);
404 tf = proto_tree_add_text(tcp_tree, offset + 13, 1, "Flags: 0x%x", th.th_flags);
405 field_tree = proto_item_add_subtree(tf, ETT_TCP_FLAGS);
406 proto_tree_add_text(field_tree, offset + 13, 1, "%s",
407 decode_boolean_bitfield(th.th_flags, TH_URG, sizeof (th.th_flags)*8,
408 "Urgent pointer", "No urgent pointer"));
409 proto_tree_add_text(field_tree, offset + 13, 1, "%s",
410 decode_boolean_bitfield(th.th_flags, TH_ACK, sizeof (th.th_flags)*8,
411 "Acknowledgment", "No acknowledgment"));
412 proto_tree_add_text(field_tree, offset + 13, 1, "%s",
413 decode_boolean_bitfield(th.th_flags, TH_PUSH, sizeof (th.th_flags)*8,
415 proto_tree_add_text(field_tree, offset + 13, 1, "%s",
416 decode_boolean_bitfield(th.th_flags, TH_RST, sizeof (th.th_flags)*8,
417 "Reset", "No reset"));
418 proto_tree_add_text(field_tree, offset + 13, 1, "%s",
419 decode_boolean_bitfield(th.th_flags, TH_SYN, sizeof (th.th_flags)*8,
421 proto_tree_add_text(field_tree, offset + 13, 1, "%s",
422 decode_boolean_bitfield(th.th_flags, TH_FIN, sizeof (th.th_flags)*8,
424 proto_tree_add_text(tcp_tree, offset + 14, 2, "Window size: %u", th.th_win);
425 proto_tree_add_text(tcp_tree, offset + 16, 2, "Checksum: 0x%04x", th.th_sum);
426 if (th.th_flags & TH_URG)
427 proto_tree_add_text(tcp_tree, offset + 18, 2, "Urgent pointer: 0x%04x",
431 /* Decode TCP options, if any. */
432 if (tree && hlen > sizeof (e_tcphdr)) {
433 /* There's more than just the fixed-length header. Decode the
435 optlen = hlen - sizeof (e_tcphdr); /* length of options, in bytes */
436 tf = proto_tree_add_text(tcp_tree, offset + 20, optlen,
437 "Options: (%d bytes)", optlen);
438 field_tree = proto_item_add_subtree(tf, ETT_TCP_OPTIONS);
439 dissect_ip_tcp_options(field_tree, &pd[offset + 20], offset + 20, optlen,
440 tcpopts, N_TCP_OPTS, TCPOPT_EOL);
443 if (check_col(fd, COL_INFO))
444 col_add_str(fd, COL_INFO, info_str);
446 /* Skip over header + options */
449 pi.srcport = th.th_sport;
450 pi.destport = th.th_dport;
452 /* Check the packet length to see if there's more data
453 (it could be an ACK-only packet) */
454 if (packet_max > offset) {
455 /* XXX - this should be handled the way UDP handles this, with a table
456 of port numbers to which stuff can be added */
457 #define PORT_IS(port) (th.th_sport == port || th.th_dport == port)
458 if (PORT_IS(TCP_PORT_PRINTER))
459 dissect_lpd(pd, offset, fd, tree);
460 else if (PORT_IS(TCP_PORT_TELNET)) {
461 pi.match_port = TCP_PORT_TELNET;
462 dissect_telnet(pd, offset, fd, tree, payload);
463 } else if (PORT_IS(TCP_PORT_FTPDATA)) {
464 pi.match_port = TCP_PORT_FTPDATA;
465 dissect_ftpdata(pd, offset, fd, tree, payload);
466 } else if (PORT_IS(TCP_PORT_FTP)) {
467 pi.match_port = TCP_PORT_FTP;
468 dissect_ftp(pd, offset, fd, tree, payload);
469 } else if (PORT_IS(TCP_PORT_POP)) {
470 pi.match_port = TCP_PORT_POP;
471 dissect_pop(pd, offset, fd, tree, payload);
472 } else if (PORT_IS(TCP_PORT_NNTP)) {
473 pi.match_port = TCP_PORT_NNTP;
474 dissect_nntp(pd, offset, fd, tree, payload);
475 } else if (PORT_IS(TCP_PORT_PPTP)) {
476 pi.match_port = TCP_PORT_PPTP;
477 dissect_pptp(pd, offset, fd, tree);
478 } else if (PORT_IS(TCP_PORT_HTTP) || PORT_IS(TCP_ALT_PORT_HTTP))
479 dissect_http(pd, offset, fd, tree);
480 else if (PORT_IS(TCP_PORT_NBSS)) {
481 pi.match_port = TCP_PORT_NBSS;
482 dissect_nbss(pd, offset, fd, tree, payload);
483 } else if (PORT_IS(TCP_PORT_RTSP))
484 dissect_rtsp(pd, offset, fd, tree);
486 /* check existence of high level protocols */
488 if (memcmp(&pd[offset], "GIOP", 4) == 0) {
489 dissect_giop(pd, offset, fd, tree);
492 dissect_data(pd, offset, fd, tree);
497 if( data_out_file ) {
498 reassemble_tcp( th.th_seq, /* sequence number */
499 ( pi.iplen -( pi.iphdrlen * 4 )-( hi_nibble(th.th_off_x2) * 4 ) ), /* length */
500 ( pd+offset ), /* data */
501 ( fd->cap_len - offset ), /* captured data length */
502 ( th.th_flags & 0x02 ), /* is syn set? */
503 pi.ip_src ); /* src ip */