1 |
|
|
/* $OpenBSD: print-tcp.c,v 1.37 2016/11/16 13:47:27 reyk Exp $ */ |
2 |
|
|
|
3 |
|
|
/* |
4 |
|
|
* Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 |
5 |
|
|
* The Regents of the University of California. All rights reserved. |
6 |
|
|
* |
7 |
|
|
* Redistribution and use in source and binary forms, with or without |
8 |
|
|
* modification, are permitted provided that: (1) source code distributions |
9 |
|
|
* retain the above copyright notice and this paragraph in its entirety, (2) |
10 |
|
|
* distributions including binary code include the above copyright notice and |
11 |
|
|
* this paragraph in its entirety in the documentation or other materials |
12 |
|
|
* provided with the distribution, and (3) all advertising materials mentioning |
13 |
|
|
* features or use of this software display the following acknowledgement: |
14 |
|
|
* ``This product includes software developed by the University of California, |
15 |
|
|
* Lawrence Berkeley Laboratory and its contributors.'' Neither the name of |
16 |
|
|
* the University nor the names of its contributors may be used to endorse |
17 |
|
|
* or promote products derived from this software without specific prior |
18 |
|
|
* written permission. |
19 |
|
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
20 |
|
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF |
21 |
|
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
22 |
|
|
*/ |
23 |
|
|
|
24 |
|
|
#include <sys/time.h> |
25 |
|
|
#include <sys/socket.h> |
26 |
|
|
|
27 |
|
|
#include <netinet/in.h> |
28 |
|
|
#include <netinet/ip.h> |
29 |
|
|
#include <netinet/ip_var.h> |
30 |
|
|
#include <netinet/tcp.h> |
31 |
|
|
#include <net/if.h> |
32 |
|
|
#include <net/pfvar.h> |
33 |
|
|
|
34 |
|
|
#include <rpc/rpc.h> |
35 |
|
|
|
36 |
|
|
#include <stdio.h> |
37 |
|
|
#include <stdlib.h> |
38 |
|
|
#include <string.h> |
39 |
|
|
#include <unistd.h> |
40 |
|
|
|
41 |
|
|
#ifdef INET6 |
42 |
|
|
#include <netinet/ip6.h> |
43 |
|
|
#endif |
44 |
|
|
|
45 |
|
|
#include "interface.h" |
46 |
|
|
#include "addrtoname.h" |
47 |
|
|
#include "extract.h" |
48 |
|
|
|
49 |
|
|
#include "nfs.h" |
50 |
|
|
|
51 |
|
|
static void print_tcp_rst_data(const u_char *sp, u_int length); |
52 |
|
|
|
53 |
|
|
#define MAX_RST_DATA_LEN 30 |
54 |
|
|
|
55 |
|
|
/* Compatibility */ |
56 |
|
|
#ifndef TCPOPT_WSCALE |
57 |
|
|
#define TCPOPT_WSCALE 3 /* window scale factor (rfc1072) */ |
58 |
|
|
#endif |
59 |
|
|
#ifndef TCPOPT_SACKOK |
60 |
|
|
#define TCPOPT_SACKOK 4 /* selective ack ok (rfc2018) */ |
61 |
|
|
#endif |
62 |
|
|
#ifndef TCPOPT_SACK |
63 |
|
|
#define TCPOPT_SACK 5 /* selective ack (rfc2018) */ |
64 |
|
|
#endif |
65 |
|
|
#ifndef TCPOLEN_SACK |
66 |
|
|
#define TCPOLEN_SACK 8 /* length of a SACK block */ |
67 |
|
|
#endif |
68 |
|
|
#ifndef TCPOPT_ECHO |
69 |
|
|
#define TCPOPT_ECHO 6 /* echo (rfc1072) */ |
70 |
|
|
#endif |
71 |
|
|
#ifndef TCPOPT_ECHOREPLY |
72 |
|
|
#define TCPOPT_ECHOREPLY 7 /* echo (rfc1072) */ |
73 |
|
|
#endif |
74 |
|
|
#ifndef TCPOPT_TIMESTAMP |
75 |
|
|
#define TCPOPT_TIMESTAMP 8 /* timestamps (rfc1323) */ |
76 |
|
|
#endif |
77 |
|
|
#ifndef TCPOPT_CC |
78 |
|
|
#define TCPOPT_CC 11 /* T/TCP CC options (rfc1644) */ |
79 |
|
|
#endif |
80 |
|
|
#ifndef TCPOPT_CCNEW |
81 |
|
|
#define TCPOPT_CCNEW 12 /* T/TCP CC options (rfc1644) */ |
82 |
|
|
#endif |
83 |
|
|
#ifndef TCPOPT_CCECHO |
84 |
|
|
#define TCPOPT_CCECHO 13 /* T/TCP CC options (rfc1644) */ |
85 |
|
|
#endif |
86 |
|
|
|
87 |
|
|
/* Definitions required for ECN |
88 |
|
|
for use if the OS running tcpdump does not have ECN */ |
89 |
|
|
#ifndef TH_ECNECHO |
90 |
|
|
#define TH_ECNECHO 0x40 /* ECN Echo in tcp header */ |
91 |
|
|
#endif |
92 |
|
|
#ifndef TH_CWR |
93 |
|
|
#define TH_CWR 0x80 /* ECN Cwnd Reduced in tcp header*/ |
94 |
|
|
#endif |
95 |
|
|
|
96 |
|
|
struct tha { |
97 |
|
|
#ifndef INET6 |
98 |
|
|
struct in_addr src; |
99 |
|
|
struct in_addr dst; |
100 |
|
|
#else |
101 |
|
|
struct in6_addr src; |
102 |
|
|
struct in6_addr dst; |
103 |
|
|
#endif /*INET6*/ |
104 |
|
|
u_int port; |
105 |
|
|
}; |
106 |
|
|
|
107 |
|
|
struct tcp_seq_hash { |
108 |
|
|
struct tcp_seq_hash *nxt; |
109 |
|
|
struct tha addr; |
110 |
|
|
tcp_seq seq; |
111 |
|
|
tcp_seq ack; |
112 |
|
|
}; |
113 |
|
|
|
114 |
|
|
#define TSEQ_HASHSIZE 919 |
115 |
|
|
|
116 |
|
|
/* These tcp optinos do not have the size octet */ |
117 |
|
|
#define ZEROLENOPT(o) ((o) == TCPOPT_EOL || (o) == TCPOPT_NOP) |
118 |
|
|
|
119 |
|
|
static struct tcp_seq_hash tcp_seq_hash[TSEQ_HASHSIZE]; |
120 |
|
|
|
121 |
|
|
#ifndef BGP_PORT |
122 |
|
|
#define BGP_PORT 179 |
123 |
|
|
#endif |
124 |
|
|
#define NETBIOS_SSN_PORT 139 |
125 |
|
|
|
126 |
|
|
/* OpenFlow TCP ports. */ |
127 |
|
|
#define OLD_OFP_PORT 6633 |
128 |
|
|
#define OFP_PORT 6653 |
129 |
|
|
|
130 |
|
|
static int tcp_cksum(const struct ip *ip, const struct tcphdr *tp, int len) |
131 |
|
|
{ |
132 |
|
|
union phu { |
133 |
|
|
struct phdr { |
134 |
|
|
u_int32_t src; |
135 |
|
|
u_int32_t dst; |
136 |
|
|
u_char mbz; |
137 |
|
|
u_char proto; |
138 |
|
|
u_int16_t len; |
139 |
|
|
} ph; |
140 |
|
|
u_int16_t pa[6]; |
141 |
|
|
} phu; |
142 |
|
|
const u_int16_t *sp; |
143 |
|
|
u_int32_t sum; |
144 |
|
|
|
145 |
|
|
/* pseudo-header.. */ |
146 |
|
|
phu.ph.len = htons((u_int16_t)len); |
147 |
|
|
phu.ph.mbz = 0; |
148 |
|
|
phu.ph.proto = IPPROTO_TCP; |
149 |
|
|
memcpy(&phu.ph.src, &ip->ip_src.s_addr, sizeof(u_int32_t)); |
150 |
|
|
memcpy(&phu.ph.dst, &ip->ip_dst.s_addr, sizeof(u_int32_t)); |
151 |
|
|
|
152 |
|
|
sp = &phu.pa[0]; |
153 |
|
|
sum = sp[0]+sp[1]+sp[2]+sp[3]+sp[4]+sp[5]; |
154 |
|
|
|
155 |
|
|
return in_cksum((u_short *)tp, len, sum); |
156 |
|
|
} |
157 |
|
|
|
158 |
|
|
#ifdef INET6 |
159 |
|
|
static int tcp6_cksum(const struct ip6_hdr *ip6, const struct tcphdr *tp, |
160 |
|
|
u_int len) |
161 |
|
|
{ |
162 |
|
|
union { |
163 |
|
|
struct { |
164 |
|
|
struct in6_addr ph_src; |
165 |
|
|
struct in6_addr ph_dst; |
166 |
|
|
u_int32_t ph_len; |
167 |
|
|
u_int8_t ph_zero[3]; |
168 |
|
|
u_int8_t ph_nxt; |
169 |
|
|
} ph; |
170 |
|
|
u_int16_t pa[20]; |
171 |
|
|
} phu; |
172 |
|
|
size_t i; |
173 |
|
|
u_int32_t sum = 0; |
174 |
|
|
|
175 |
|
|
/* pseudo-header */ |
176 |
|
|
memset(&phu, 0, sizeof(phu)); |
177 |
|
|
phu.ph.ph_src = ip6->ip6_src; |
178 |
|
|
phu.ph.ph_dst = ip6->ip6_dst; |
179 |
|
|
phu.ph.ph_len = htonl(len); |
180 |
|
|
phu.ph.ph_nxt = IPPROTO_TCP; |
181 |
|
|
|
182 |
|
|
for (i = 0; i < sizeof(phu.pa) / sizeof(phu.pa[0]); i++) |
183 |
|
|
sum += phu.pa[i]; |
184 |
|
|
|
185 |
|
|
return in_cksum((u_short *)tp, len, sum); |
186 |
|
|
} |
187 |
|
|
#endif |
188 |
|
|
|
189 |
|
|
|
190 |
|
|
void |
191 |
|
|
tcp_print(const u_char *bp, u_int length, const u_char *bp2) |
192 |
|
|
{ |
193 |
|
|
const struct tcphdr *tp; |
194 |
|
|
const struct ip *ip; |
195 |
|
|
u_char flags; |
196 |
|
|
int hlen; |
197 |
|
|
char ch; |
198 |
|
|
struct tcp_seq_hash *th = NULL; |
199 |
|
|
int rev = 0; |
200 |
|
|
u_int16_t sport, dport, win, urp; |
201 |
|
|
tcp_seq seq, ack; |
202 |
|
|
#ifdef INET6 |
203 |
|
|
const struct ip6_hdr *ip6; |
204 |
|
|
#endif |
205 |
|
|
|
206 |
|
|
tp = (struct tcphdr *)bp; |
207 |
|
|
switch (((struct ip *)bp2)->ip_v) { |
208 |
|
|
case 4: |
209 |
|
|
ip = (struct ip *)bp2; |
210 |
|
|
#ifdef INET6 |
211 |
|
|
ip6 = NULL; |
212 |
|
|
#endif |
213 |
|
|
break; |
214 |
|
|
#ifdef INET6 |
215 |
|
|
case 6: |
216 |
|
|
ip = NULL; |
217 |
|
|
ip6 = (struct ip6_hdr *)bp2; |
218 |
|
|
break; |
219 |
|
|
#endif |
220 |
|
|
default: |
221 |
|
|
(void)printf("invalid ip version"); |
222 |
|
|
return; |
223 |
|
|
} |
224 |
|
|
|
225 |
|
|
ch = '\0'; |
226 |
|
|
if (length < sizeof(*tp)) { |
227 |
|
|
(void)printf("truncated-tcp %u", length); |
228 |
|
|
return; |
229 |
|
|
} |
230 |
|
|
|
231 |
|
|
if (!TTEST(tp->th_dport)) { |
232 |
|
|
#ifdef INET6 |
233 |
|
|
if (ip6) { |
234 |
|
|
(void)printf("%s > %s: [|tcp]", |
235 |
|
|
ip6addr_string(&ip6->ip6_src), |
236 |
|
|
ip6addr_string(&ip6->ip6_dst)); |
237 |
|
|
} else |
238 |
|
|
#endif /*INET6*/ |
239 |
|
|
{ |
240 |
|
|
(void)printf("%s > %s: [|tcp]", |
241 |
|
|
ipaddr_string(&ip->ip_src), |
242 |
|
|
ipaddr_string(&ip->ip_dst)); |
243 |
|
|
} |
244 |
|
|
return; |
245 |
|
|
} |
246 |
|
|
|
247 |
|
|
sport = ntohs(tp->th_sport); |
248 |
|
|
dport = ntohs(tp->th_dport); |
249 |
|
|
|
250 |
|
|
#ifdef INET6 |
251 |
|
|
if (ip6) { |
252 |
|
|
if (ip6->ip6_nxt == IPPROTO_TCP) { |
253 |
|
|
(void)printf("%s.%s > %s.%s: ", |
254 |
|
|
ip6addr_string(&ip6->ip6_src), |
255 |
|
|
tcpport_string(sport), |
256 |
|
|
ip6addr_string(&ip6->ip6_dst), |
257 |
|
|
tcpport_string(dport)); |
258 |
|
|
} else { |
259 |
|
|
(void)printf("%s > %s: ", |
260 |
|
|
tcpport_string(sport), tcpport_string(dport)); |
261 |
|
|
} |
262 |
|
|
} else |
263 |
|
|
#endif /*INET6*/ |
264 |
|
|
{ |
265 |
|
|
if (ip->ip_p == IPPROTO_TCP) { |
266 |
|
|
(void)printf("%s.%s > %s.%s: ", |
267 |
|
|
ipaddr_string(&ip->ip_src), |
268 |
|
|
tcpport_string(sport), |
269 |
|
|
ipaddr_string(&ip->ip_dst), |
270 |
|
|
tcpport_string(dport)); |
271 |
|
|
} else { |
272 |
|
|
(void)printf("%s > %s: ", |
273 |
|
|
tcpport_string(sport), tcpport_string(dport)); |
274 |
|
|
} |
275 |
|
|
} |
276 |
|
|
|
277 |
|
|
if (!qflag && TTEST(tp->th_seq) && !TTEST(tp->th_ack)) |
278 |
|
|
(void)printf("%u ", ntohl(tp->th_seq)); |
279 |
|
|
|
280 |
|
|
TCHECK(*tp); |
281 |
|
|
seq = ntohl(tp->th_seq); |
282 |
|
|
ack = ntohl(tp->th_ack); |
283 |
|
|
win = ntohs(tp->th_win); |
284 |
|
|
urp = ntohs(tp->th_urp); |
285 |
|
|
hlen = tp->th_off * 4; |
286 |
|
|
|
287 |
|
|
if (qflag) { |
288 |
|
|
(void)printf("tcp %d", length - tp->th_off * 4); |
289 |
|
|
return; |
290 |
|
|
} else if (packettype != PT_TCP) { |
291 |
|
|
|
292 |
|
|
/* |
293 |
|
|
* If data present and NFS port used, assume NFS. |
294 |
|
|
* Pass offset of data plus 4 bytes for RPC TCP msg length |
295 |
|
|
* to NFS print routines. |
296 |
|
|
*/ |
297 |
|
|
u_int len = length - hlen; |
298 |
|
|
if ((u_char *)tp + 4 + sizeof(struct rpc_msg) <= snapend && |
299 |
|
|
dport == NFS_PORT) { |
300 |
|
|
nfsreq_print((u_char *)tp + hlen + 4, len, bp2); |
301 |
|
|
return; |
302 |
|
|
} else if ((u_char *)tp + 4 + |
303 |
|
|
sizeof(struct rpc_msg) <= snapend && sport == NFS_PORT) { |
304 |
|
|
nfsreply_print((u_char *)tp + hlen + 4, len, bp2); |
305 |
|
|
return; |
306 |
|
|
} |
307 |
|
|
} |
308 |
|
|
if ((flags = tp->th_flags) & (TH_SYN|TH_FIN|TH_RST|TH_PUSH| |
309 |
|
|
TH_ECNECHO|TH_CWR)) { |
310 |
|
|
if (flags & TH_SYN) |
311 |
|
|
putchar('S'); |
312 |
|
|
if (flags & TH_FIN) |
313 |
|
|
putchar('F'); |
314 |
|
|
if (flags & TH_RST) |
315 |
|
|
putchar('R'); |
316 |
|
|
if (flags & TH_PUSH) |
317 |
|
|
putchar('P'); |
318 |
|
|
if (flags & TH_CWR) |
319 |
|
|
putchar('W'); /* congestion _W_indow reduced (ECN) */ |
320 |
|
|
if (flags & TH_ECNECHO) |
321 |
|
|
putchar('E'); /* ecn _E_cho sent (ECN) */ |
322 |
|
|
} else |
323 |
|
|
putchar('.'); |
324 |
|
|
|
325 |
|
|
if (!Sflag && (flags & TH_ACK)) { |
326 |
|
|
struct tha tha; |
327 |
|
|
/* |
328 |
|
|
* Find (or record) the initial sequence numbers for |
329 |
|
|
* this conversation. (we pick an arbitrary |
330 |
|
|
* collating order so there's only one entry for |
331 |
|
|
* both directions). |
332 |
|
|
*/ |
333 |
|
|
#ifdef INET6 |
334 |
|
|
bzero(&tha, sizeof(tha)); |
335 |
|
|
rev = 0; |
336 |
|
|
if (ip6) { |
337 |
|
|
if (sport > dport) { |
338 |
|
|
rev = 1; |
339 |
|
|
} else if (sport == dport) { |
340 |
|
|
int i; |
341 |
|
|
|
342 |
|
|
for (i = 0; i < 4; i++) { |
343 |
|
|
if (((u_int32_t *)(&ip6->ip6_src))[i] > |
344 |
|
|
((u_int32_t *)(&ip6->ip6_dst))[i]) { |
345 |
|
|
rev = 1; |
346 |
|
|
break; |
347 |
|
|
} |
348 |
|
|
} |
349 |
|
|
} |
350 |
|
|
if (rev) { |
351 |
|
|
tha.src = ip6->ip6_dst; |
352 |
|
|
tha.dst = ip6->ip6_src; |
353 |
|
|
tha.port = dport << 16 | sport; |
354 |
|
|
} else { |
355 |
|
|
tha.dst = ip6->ip6_dst; |
356 |
|
|
tha.src = ip6->ip6_src; |
357 |
|
|
tha.port = sport << 16 | dport; |
358 |
|
|
} |
359 |
|
|
} else { |
360 |
|
|
if (sport > dport || |
361 |
|
|
(sport == dport && |
362 |
|
|
ip->ip_src.s_addr > ip->ip_dst.s_addr)) { |
363 |
|
|
rev = 1; |
364 |
|
|
} |
365 |
|
|
if (rev) { |
366 |
|
|
*(struct in_addr *)&tha.src = ip->ip_dst; |
367 |
|
|
*(struct in_addr *)&tha.dst = ip->ip_src; |
368 |
|
|
tha.port = dport << 16 | sport; |
369 |
|
|
} else { |
370 |
|
|
*(struct in_addr *)&tha.dst = ip->ip_dst; |
371 |
|
|
*(struct in_addr *)&tha.src = ip->ip_src; |
372 |
|
|
tha.port = sport << 16 | dport; |
373 |
|
|
} |
374 |
|
|
} |
375 |
|
|
#else |
376 |
|
|
if (sport < dport || |
377 |
|
|
(sport == dport && |
378 |
|
|
ip->ip_src.s_addr < ip->ip_dst.s_addr)) { |
379 |
|
|
tha.src = ip->ip_src, tha.dst = ip->ip_dst; |
380 |
|
|
tha.port = sport << 16 | dport; |
381 |
|
|
rev = 0; |
382 |
|
|
} else { |
383 |
|
|
tha.src = ip->ip_dst, tha.dst = ip->ip_src; |
384 |
|
|
tha.port = dport << 16 | sport; |
385 |
|
|
rev = 1; |
386 |
|
|
} |
387 |
|
|
#endif |
388 |
|
|
|
389 |
|
|
for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE]; |
390 |
|
|
th->nxt; th = th->nxt) |
391 |
|
|
if (!memcmp((char *)&tha, (char *)&th->addr, |
392 |
|
|
sizeof(th->addr))) |
393 |
|
|
break; |
394 |
|
|
|
395 |
|
|
if (!th->nxt || flags & TH_SYN) { |
396 |
|
|
/* didn't find it or new conversation */ |
397 |
|
|
if (th->nxt == NULL) { |
398 |
|
|
th->nxt = calloc(1, sizeof(*th)); |
399 |
|
|
if (th->nxt == NULL) |
400 |
|
|
error("tcp_print: calloc"); |
401 |
|
|
} |
402 |
|
|
th->addr = tha; |
403 |
|
|
if (rev) |
404 |
|
|
th->ack = seq, th->seq = ack - 1; |
405 |
|
|
else |
406 |
|
|
th->seq = seq, th->ack = ack - 1; |
407 |
|
|
} else { |
408 |
|
|
if (rev) |
409 |
|
|
seq -= th->ack, ack -= th->seq; |
410 |
|
|
else |
411 |
|
|
seq -= th->seq, ack -= th->ack; |
412 |
|
|
} |
413 |
|
|
} |
414 |
|
|
hlen = tp->th_off * 4; |
415 |
|
|
if (hlen > length) { |
416 |
|
|
(void)printf(" [bad hdr length]"); |
417 |
|
|
return; |
418 |
|
|
} |
419 |
|
|
|
420 |
|
|
if (ip && ip->ip_v == 4 && vflag) { |
421 |
|
|
if (TTEST2(tp->th_sport, length)) { |
422 |
|
|
u_int16_t sum, tcp_sum; |
423 |
|
|
sum = tcp_cksum(ip, tp, length); |
424 |
|
|
if (sum != 0) { |
425 |
|
|
tcp_sum = EXTRACT_16BITS(&tp->th_sum); |
426 |
|
|
(void)printf(" [bad tcp cksum %x! -> %x]", tcp_sum, |
427 |
|
|
in_cksum_shouldbe(tcp_sum, sum)); |
428 |
|
|
} else |
429 |
|
|
(void)printf(" [tcp sum ok]"); |
430 |
|
|
} |
431 |
|
|
} |
432 |
|
|
#ifdef INET6 |
433 |
|
|
if (ip6 && ip6->ip6_plen && vflag) { |
434 |
|
|
if (TTEST2(tp->th_sport, length)) { |
435 |
|
|
u_int16_t sum, tcp_sum; |
436 |
|
|
sum = tcp6_cksum(ip6, tp, length); |
437 |
|
|
if (sum != 0) { |
438 |
|
|
tcp_sum = EXTRACT_16BITS(&tp->th_sum); |
439 |
|
|
(void)printf(" [bad tcp cksum %x! -> %x]", tcp_sum, |
440 |
|
|
in_cksum_shouldbe(tcp_sum, sum)); |
441 |
|
|
} else |
442 |
|
|
(void)printf(" [tcp sum ok]"); |
443 |
|
|
} |
444 |
|
|
} |
445 |
|
|
#endif |
446 |
|
|
|
447 |
|
|
/* OS Fingerprint */ |
448 |
|
|
if (oflag && (flags & (TH_SYN|TH_ACK)) == TH_SYN) { |
449 |
|
|
struct pf_osfp_enlist *head = NULL; |
450 |
|
|
struct pf_osfp_entry *fp; |
451 |
|
|
unsigned long left; |
452 |
|
|
left = (unsigned long)(snapend - (const u_char *)tp); |
453 |
|
|
|
454 |
|
|
if (left >= hlen) |
455 |
|
|
head = pf_osfp_fingerprint_hdr(ip, ip6, tp); |
456 |
|
|
if (head) { |
457 |
|
|
int prev = 0; |
458 |
|
|
printf(" (src OS:"); |
459 |
|
|
SLIST_FOREACH(fp, head, fp_entry) { |
460 |
|
|
if (fp->fp_enflags & PF_OSFP_EXPANDED) |
461 |
|
|
continue; |
462 |
|
|
if (prev) |
463 |
|
|
printf(","); |
464 |
|
|
printf(" %s", fp->fp_class_nm); |
465 |
|
|
if (fp->fp_version_nm[0]) |
466 |
|
|
printf(" %s", fp->fp_version_nm); |
467 |
|
|
if (fp->fp_subtype_nm[0]) |
468 |
|
|
printf(" %s", fp->fp_subtype_nm); |
469 |
|
|
prev = 1; |
470 |
|
|
} |
471 |
|
|
printf(")"); |
472 |
|
|
} else { |
473 |
|
|
if (left < hlen) |
474 |
|
|
printf(" (src OS: short-pkt)"); |
475 |
|
|
else |
476 |
|
|
printf(" (src OS: unknown)"); |
477 |
|
|
} |
478 |
|
|
} |
479 |
|
|
|
480 |
|
|
length -= hlen; |
481 |
|
|
if (vflag > 1 || length > 0 || flags & (TH_SYN | TH_FIN | TH_RST)) |
482 |
|
|
(void)printf(" %u:%u(%u)", seq, seq + length, length); |
483 |
|
|
if (flags & TH_ACK) |
484 |
|
|
(void)printf(" ack %u", ack); |
485 |
|
|
|
486 |
|
|
(void)printf(" win %u", win); |
487 |
|
|
|
488 |
|
|
if (flags & TH_URG) |
489 |
|
|
(void)printf(" urg %u", urp); |
490 |
|
|
/* |
491 |
|
|
* Handle any options. |
492 |
|
|
*/ |
493 |
|
|
if ((hlen -= sizeof(*tp)) > 0) { |
494 |
|
|
const u_char *cp; |
495 |
|
|
int i, opt, len, datalen; |
496 |
|
|
|
497 |
|
|
cp = (const u_char *)tp + sizeof(*tp); |
498 |
|
|
putchar(' '); |
499 |
|
|
ch = '<'; |
500 |
|
|
while (hlen > 0) { |
501 |
|
|
putchar(ch); |
502 |
|
|
TCHECK(*cp); |
503 |
|
|
opt = *cp++; |
504 |
|
|
if (ZEROLENOPT(opt)) |
505 |
|
|
len = 1; |
506 |
|
|
else { |
507 |
|
|
TCHECK(*cp); |
508 |
|
|
len = *cp++; /* total including type, len */ |
509 |
|
|
if (len < 2 || len > hlen) |
510 |
|
|
goto bad; |
511 |
|
|
--hlen; /* account for length byte */ |
512 |
|
|
} |
513 |
|
|
--hlen; /* account for type byte */ |
514 |
|
|
datalen = 0; |
515 |
|
|
|
516 |
|
|
/* Bail if "l" bytes of data are not left or were not captured */ |
517 |
|
|
#define LENCHECK(l) { if ((l) > hlen) goto bad; TCHECK2(*cp, l); } |
518 |
|
|
|
519 |
|
|
switch (opt) { |
520 |
|
|
|
521 |
|
|
case TCPOPT_MAXSEG: |
522 |
|
|
(void)printf("mss"); |
523 |
|
|
datalen = 2; |
524 |
|
|
LENCHECK(datalen); |
525 |
|
|
(void)printf(" %u", EXTRACT_16BITS(cp)); |
526 |
|
|
|
527 |
|
|
break; |
528 |
|
|
|
529 |
|
|
case TCPOPT_EOL: |
530 |
|
|
(void)printf("eol"); |
531 |
|
|
break; |
532 |
|
|
|
533 |
|
|
case TCPOPT_NOP: |
534 |
|
|
(void)printf("nop"); |
535 |
|
|
break; |
536 |
|
|
|
537 |
|
|
case TCPOPT_WSCALE: |
538 |
|
|
(void)printf("wscale"); |
539 |
|
|
datalen = 1; |
540 |
|
|
LENCHECK(datalen); |
541 |
|
|
(void)printf(" %u", *cp); |
542 |
|
|
break; |
543 |
|
|
|
544 |
|
|
case TCPOPT_SACKOK: |
545 |
|
|
(void)printf("sackOK"); |
546 |
|
|
if (len != 2) |
547 |
|
|
(void)printf("[len %d]", len); |
548 |
|
|
break; |
549 |
|
|
|
550 |
|
|
case TCPOPT_SACK: |
551 |
|
|
{ |
552 |
|
|
u_long s, e; |
553 |
|
|
|
554 |
|
|
datalen = len - 2; |
555 |
|
|
if ((datalen % TCPOLEN_SACK) != 0 || |
556 |
|
|
!(flags & TH_ACK)) { |
557 |
|
|
(void)printf("malformed sack "); |
558 |
|
|
(void)printf("[len %d] ", datalen); |
559 |
|
|
break; |
560 |
|
|
} |
561 |
|
|
printf("sack %d ", datalen/TCPOLEN_SACK); |
562 |
|
|
for (i = 0; i < datalen; i += TCPOLEN_SACK) { |
563 |
|
|
LENCHECK (i + TCPOLEN_SACK); |
564 |
|
|
s = EXTRACT_32BITS(cp + i); |
565 |
|
|
e = EXTRACT_32BITS(cp + i + 4); |
566 |
|
|
if (!Sflag) { |
567 |
|
|
if (rev) { |
568 |
|
|
s -= th->seq; |
569 |
|
|
e -= th->seq; |
570 |
|
|
} else { |
571 |
|
|
s -= th->ack; |
572 |
|
|
e -= th->ack; |
573 |
|
|
} |
574 |
|
|
} |
575 |
|
|
(void) printf("{%lu:%lu} ", s, e); |
576 |
|
|
} |
577 |
|
|
break; |
578 |
|
|
} |
579 |
|
|
case TCPOPT_ECHO: |
580 |
|
|
(void)printf("echo"); |
581 |
|
|
datalen = 4; |
582 |
|
|
LENCHECK(datalen); |
583 |
|
|
(void)printf(" %u", EXTRACT_32BITS(cp)); |
584 |
|
|
break; |
585 |
|
|
|
586 |
|
|
case TCPOPT_ECHOREPLY: |
587 |
|
|
(void)printf("echoreply"); |
588 |
|
|
datalen = 4; |
589 |
|
|
LENCHECK(datalen); |
590 |
|
|
(void)printf(" %u", EXTRACT_32BITS(cp)); |
591 |
|
|
break; |
592 |
|
|
|
593 |
|
|
case TCPOPT_TIMESTAMP: |
594 |
|
|
(void)printf("timestamp"); |
595 |
|
|
datalen = 8; |
596 |
|
|
LENCHECK(4); |
597 |
|
|
(void)printf(" %u", EXTRACT_32BITS(cp)); |
598 |
|
|
LENCHECK(datalen); |
599 |
|
|
(void)printf(" %u", EXTRACT_32BITS(cp + 4)); |
600 |
|
|
break; |
601 |
|
|
|
602 |
|
|
case TCPOPT_CC: |
603 |
|
|
(void)printf("cc"); |
604 |
|
|
datalen = 4; |
605 |
|
|
LENCHECK(datalen); |
606 |
|
|
(void)printf(" %u", EXTRACT_32BITS(cp)); |
607 |
|
|
break; |
608 |
|
|
|
609 |
|
|
case TCPOPT_CCNEW: |
610 |
|
|
(void)printf("ccnew"); |
611 |
|
|
datalen = 4; |
612 |
|
|
LENCHECK(datalen); |
613 |
|
|
(void)printf(" %u", EXTRACT_32BITS(cp)); |
614 |
|
|
break; |
615 |
|
|
|
616 |
|
|
case TCPOPT_CCECHO: |
617 |
|
|
(void)printf("ccecho"); |
618 |
|
|
datalen = 4; |
619 |
|
|
LENCHECK(datalen); |
620 |
|
|
(void)printf(" %u", EXTRACT_32BITS(cp)); |
621 |
|
|
break; |
622 |
|
|
|
623 |
|
|
case TCPOPT_SIGNATURE: |
624 |
|
|
(void)printf("tcpmd5:"); |
625 |
|
|
datalen = len - 2; |
626 |
|
|
for (i = 0; i < datalen; ++i) { |
627 |
|
|
LENCHECK(i+1); |
628 |
|
|
(void)printf("%02x", cp[i]); |
629 |
|
|
} |
630 |
|
|
break; |
631 |
|
|
|
632 |
|
|
default: |
633 |
|
|
(void)printf("opt-%d:", opt); |
634 |
|
|
datalen = len - 2; |
635 |
|
|
for (i = 0; i < datalen; ++i) { |
636 |
|
|
LENCHECK(i+1); |
637 |
|
|
(void)printf("%02x", cp[i]); |
638 |
|
|
} |
639 |
|
|
break; |
640 |
|
|
} |
641 |
|
|
|
642 |
|
|
/* Account for data printed */ |
643 |
|
|
cp += datalen; |
644 |
|
|
hlen -= datalen; |
645 |
|
|
|
646 |
|
|
/* Check specification against observed length */ |
647 |
|
|
++datalen; /* option octet */ |
648 |
|
|
if (!ZEROLENOPT(opt)) |
649 |
|
|
++datalen; /* size octet */ |
650 |
|
|
if (datalen != len) |
651 |
|
|
(void)printf("[len %d]", len); |
652 |
|
|
ch = ','; |
653 |
|
|
if (opt == TCPOPT_EOL) |
654 |
|
|
break; |
655 |
|
|
} |
656 |
|
|
putchar('>'); |
657 |
|
|
} |
658 |
|
|
|
659 |
|
|
if (length <= 0) |
660 |
|
|
return; |
661 |
|
|
|
662 |
|
|
/* |
663 |
|
|
* Decode payload if necessary. |
664 |
|
|
*/ |
665 |
|
|
bp += (tp->th_off * 4); |
666 |
|
|
if (flags & TH_RST) { |
667 |
|
|
if (vflag) |
668 |
|
|
print_tcp_rst_data(bp, length); |
669 |
|
|
} else { |
670 |
|
|
if (sport == BGP_PORT || dport == BGP_PORT) |
671 |
|
|
bgp_print(bp, length); |
672 |
|
|
else if (sport == OLD_OFP_PORT || dport == OLD_OFP_PORT || |
673 |
|
|
sport == OFP_PORT || dport == OFP_PORT) |
674 |
|
|
ofp_print(bp, length); |
675 |
|
|
#if 0 |
676 |
|
|
else if (sport == NETBIOS_SSN_PORT || dport == NETBIOS_SSN_PORT) |
677 |
|
|
nbt_tcp_print(bp, length); |
678 |
|
|
#endif |
679 |
|
|
} |
680 |
|
|
return; |
681 |
|
|
bad: |
682 |
|
|
fputs("[bad opt]", stdout); |
683 |
|
|
if (ch != '\0') |
684 |
|
|
putchar('>'); |
685 |
|
|
return; |
686 |
|
|
trunc: |
687 |
|
|
fputs("[|tcp]", stdout); |
688 |
|
|
if (ch != '\0') |
689 |
|
|
putchar('>'); |
690 |
|
|
} |
691 |
|
|
|
692 |
|
|
|
693 |
|
|
/* |
694 |
|
|
* RFC1122 says the following on data in RST segments: |
695 |
|
|
* |
696 |
|
|
* 4.2.2.12 RST Segment: RFC-793 Section 3.4 |
697 |
|
|
* |
698 |
|
|
* A TCP SHOULD allow a received RST segment to include data. |
699 |
|
|
* |
700 |
|
|
* DISCUSSION |
701 |
|
|
* It has been suggested that a RST segment could contain |
702 |
|
|
* ASCII text that encoded and explained the cause of the |
703 |
|
|
* RST. No standard has yet been established for such |
704 |
|
|
* data. |
705 |
|
|
* |
706 |
|
|
*/ |
707 |
|
|
|
708 |
|
|
static void |
709 |
|
|
print_tcp_rst_data(const u_char *sp, u_int length) |
710 |
|
|
{ |
711 |
|
|
int c; |
712 |
|
|
|
713 |
|
|
if (TTEST2(*sp, length)) |
714 |
|
|
printf(" [RST"); |
715 |
|
|
else |
716 |
|
|
printf(" [!RST"); |
717 |
|
|
if (length > MAX_RST_DATA_LEN) { |
718 |
|
|
length = MAX_RST_DATA_LEN; /* can use -X for longer */ |
719 |
|
|
putchar('+'); /* indicate we truncate */ |
720 |
|
|
} |
721 |
|
|
putchar(' '); |
722 |
|
|
while (length-- && sp < snapend) { |
723 |
|
|
c = *sp++; |
724 |
|
|
safeputchar(c); |
725 |
|
|
} |
726 |
|
|
putchar(']'); |
727 |
|
|
} |