Fix markup. Fix backslashes to surive roff.
[netbsd-mini2440.git] / dist / tcpdump / print-tcp.c
bloba3db8a1b8d0a3f75ae4a05d62a805603bfb3c176
1 /* $NetBSD: print-tcp.c,v 1.8 2007/07/24 11:53:48 drochner Exp $ */
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.
7 * Copyright (c) 1999-2004 The tcpdump.org project
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that: (1) source code distributions
11 * retain the above copyright notice and this paragraph in its entirety, (2)
12 * distributions including binary code include the above copyright notice and
13 * this paragraph in its entirety in the documentation or other materials
14 * provided with the distribution, and (3) all advertising materials mentioning
15 * features or use of this software display the following acknowledgement:
16 * ``This product includes software developed by the University of California,
17 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
18 * the University nor the names of its contributors may be used to endorse
19 * or promote products derived from this software without specific prior
20 * written permission.
21 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
22 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
23 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
26 #include <sys/cdefs.h>
27 #ifndef lint
28 #if 0
29 static const char rcsid[] _U_ =
30 "@(#) Header: /tcpdump/master/tcpdump/print-tcp.c,v 1.120.2.3 2005/10/16 06:05:46 guy Exp (LBL)";
31 #else
32 __RCSID("$NetBSD: print-tcp.c,v 1.8 2007/07/24 11:53:48 drochner Exp $");
33 #endif
34 #endif
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
40 #include <tcpdump-stdinc.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
46 #include "interface.h"
47 #include "addrtoname.h"
48 #include "extract.h"
50 #include "tcp.h"
52 #include "ip.h"
53 #ifdef INET6
54 #include "ip6.h"
55 #endif
56 #include "ipproto.h"
57 #include "rpc_auth.h"
58 #include "rpc_msg.h"
60 #include "nameser.h"
62 #ifdef HAVE_LIBCRYPTO
63 #include <openssl/md5.h>
65 #define SIGNATURE_VALID 0
66 #define SIGNATURE_INVALID 1
67 #define CANT_CHECK_SIGNATURE 2
69 static int tcp_verify_signature(const struct ip *ip, const struct tcphdr *tp,
70 const u_char *data, int length, const u_char *rcvsig);
71 #endif
73 static void print_tcp_rst_data(register const u_char *sp, u_int length);
75 #define MAX_RST_DATA_LEN 30
78 struct tha {
79 #ifndef INET6
80 struct in_addr src;
81 struct in_addr dst;
82 #else
83 struct in6_addr src;
84 struct in6_addr dst;
85 #endif /*INET6*/
86 u_int port;
89 struct tcp_seq_hash {
90 struct tcp_seq_hash *nxt;
91 struct tha addr;
92 tcp_seq seq;
93 tcp_seq ack;
96 #define TSEQ_HASHSIZE 919
98 /* These tcp optinos do not have the size octet */
99 #define ZEROLENOPT(o) ((o) == TCPOPT_EOL || (o) == TCPOPT_NOP)
101 static struct tcp_seq_hash tcp_seq_hash[TSEQ_HASHSIZE];
104 #ifndef TELNET_PORT
105 #define TELNET_PORT 23
106 #endif
107 #ifndef BGP_PORT
108 #define BGP_PORT 179
109 #endif
110 #define NETBIOS_SSN_PORT 139
111 #ifndef PPTP_PORT
112 #define PPTP_PORT 1723
113 #endif
114 #define BEEP_PORT 10288
115 #ifndef NFS_PORT
116 #define NFS_PORT 2049
117 #endif
118 #define MSDP_PORT 639
119 #define LDP_PORT 646
121 static int tcp_cksum(register const struct ip *ip,
122 register const struct tcphdr *tp,
123 register u_int len)
125 union phu {
126 struct phdr {
127 u_int32_t src;
128 u_int32_t dst;
129 u_char mbz;
130 u_char proto;
131 u_int16_t len;
132 } ph;
133 u_int16_t pa[6];
134 } phu;
135 const u_int16_t *sp;
137 /* pseudo-header.. */
138 phu.ph.len = htons((u_int16_t)len);
139 phu.ph.mbz = 0;
140 phu.ph.proto = IPPROTO_TCP;
141 memcpy(&phu.ph.src, &ip->ip_src.s_addr, sizeof(u_int32_t));
142 if (IP_HL(ip) == 5)
143 memcpy(&phu.ph.dst, &ip->ip_dst.s_addr, sizeof(u_int32_t));
144 else
145 phu.ph.dst = ip_finddst(ip);
147 sp = &phu.pa[0];
148 return in_cksum((u_short *)tp, len,
149 sp[0]+sp[1]+sp[2]+sp[3]+sp[4]+sp[5]);
152 #ifdef INET6
153 static int tcp6_cksum(const struct ip6_hdr *ip6, const struct tcphdr *tp,
154 u_int len)
156 size_t i;
157 register const u_int16_t *sp;
158 u_int32_t sum;
159 union {
160 struct {
161 struct in6_addr ph_src;
162 struct in6_addr ph_dst;
163 u_int32_t ph_len;
164 u_int8_t ph_zero[3];
165 u_int8_t ph_nxt;
166 } ph;
167 u_int16_t pa[20];
168 } phu;
170 /* pseudo-header */
171 memset(&phu, 0, sizeof(phu));
172 phu.ph.ph_src = ip6->ip6_src;
173 phu.ph.ph_dst = ip6->ip6_dst;
174 phu.ph.ph_len = htonl(len);
175 phu.ph.ph_nxt = IPPROTO_TCP;
177 sum = 0;
178 for (i = 0; i < sizeof(phu.pa) / sizeof(phu.pa[0]); i++)
179 sum += phu.pa[i];
181 sp = (const u_int16_t *)tp;
183 for (i = 0; i < (len & ~1); i += 2)
184 sum += *sp++;
186 if (len & 1)
187 sum += htons((*(const u_int8_t *)sp) << 8);
189 while (sum > 0xffff)
190 sum = (sum & 0xffff) + (sum >> 16);
191 sum = ~sum & 0xffff;
193 return (sum);
195 #endif
197 void
198 tcp_print(register const u_char *bp, register u_int length,
199 register const u_char *bp2, int fragmented)
201 register const struct tcphdr *tp;
202 register const struct ip *ip;
203 register u_char flags;
204 register u_int hlen;
205 register char ch;
206 u_int16_t sport, dport, win, urp;
207 u_int32_t seq, ack, thseq, thack;
208 int threv;
209 #ifdef INET6
210 register const struct ip6_hdr *ip6;
211 #endif
213 tp = (struct tcphdr *)bp;
214 ip = (struct ip *)bp2;
215 #ifdef INET6
216 if (IP_V(ip) == 6)
217 ip6 = (struct ip6_hdr *)bp2;
218 else
219 ip6 = NULL;
220 #endif /*INET6*/
221 ch = '\0';
222 if (!TTEST(tp->th_dport)) {
223 (void)printf("%s > %s: [|tcp]",
224 ipaddr_string(&ip->ip_src),
225 ipaddr_string(&ip->ip_dst));
226 return;
229 sport = EXTRACT_16BITS(&tp->th_sport);
230 dport = EXTRACT_16BITS(&tp->th_dport);
232 hlen = TH_OFF(tp) * 4;
235 * If data present, header length valid, and NFS port used,
236 * assume NFS.
237 * Pass offset of data plus 4 bytes for RPC TCP msg length
238 * to NFS print routines.
240 if (!qflag && hlen >= sizeof(*tp) && hlen <= length) {
241 if ((u_char *)tp + 4 + sizeof(struct sunrpc_msg) <= snapend &&
242 dport == NFS_PORT) {
243 nfsreq_print((u_char *)tp + hlen + 4, length - hlen,
244 (u_char *)ip);
245 return;
246 } else if ((u_char *)tp + 4 + sizeof(struct sunrpc_msg)
247 <= snapend &&
248 sport == NFS_PORT) {
249 nfsreply_print((u_char *)tp + hlen + 4, length - hlen,
250 (u_char *)ip);
251 return;
254 #ifdef INET6
255 if (ip6) {
256 if (ip6->ip6_nxt == IPPROTO_TCP) {
257 (void)printf("%s.%s > %s.%s: ",
258 ip6addr_string(&ip6->ip6_src),
259 tcpport_string(sport),
260 ip6addr_string(&ip6->ip6_dst),
261 tcpport_string(dport));
262 } else {
263 (void)printf("%s > %s: ",
264 tcpport_string(sport), tcpport_string(dport));
266 } else
267 #endif /*INET6*/
269 if (ip->ip_p == IPPROTO_TCP) {
270 (void)printf("%s.%s > %s.%s: ",
271 ipaddr_string(&ip->ip_src),
272 tcpport_string(sport),
273 ipaddr_string(&ip->ip_dst),
274 tcpport_string(dport));
275 } else {
276 (void)printf("%s > %s: ",
277 tcpport_string(sport), tcpport_string(dport));
281 if (hlen < sizeof(*tp)) {
282 (void)printf(" tcp %d [bad hdr length %u - too short, < %lu]",
283 length - hlen, hlen, (unsigned long)sizeof(*tp));
284 return;
287 TCHECK(*tp);
289 seq = EXTRACT_32BITS(&tp->th_seq);
290 ack = EXTRACT_32BITS(&tp->th_ack);
291 win = EXTRACT_16BITS(&tp->th_win);
292 urp = EXTRACT_16BITS(&tp->th_urp);
294 if (qflag) {
295 (void)printf("tcp %d", length - hlen);
296 if (hlen > length) {
297 (void)printf(" [bad hdr length %u - too long, > %u]",
298 hlen, length);
300 return;
302 if ((flags = tp->th_flags) & (TH_SYN|TH_FIN|TH_RST|TH_PUSH|
303 TH_ECNECHO|TH_CWR)) {
304 if (flags & TH_SYN)
305 putchar('S');
306 if (flags & TH_FIN)
307 putchar('F');
308 if (flags & TH_RST)
309 putchar('R');
310 if (flags & TH_PUSH)
311 putchar('P');
312 if (flags & TH_CWR)
313 putchar('W'); /* congestion _W_indow reduced (ECN) */
314 if (flags & TH_ECNECHO)
315 putchar('E'); /* ecn _E_cho sent (ECN) */
316 } else
317 putchar('.');
319 if (!Sflag && (flags & TH_ACK)) {
320 register struct tcp_seq_hash *th;
321 const void *src, *dst;
322 register int rev;
323 struct tha tha;
325 * Find (or record) the initial sequence numbers for
326 * this conversation. (we pick an arbitrary
327 * collating order so there's only one entry for
328 * both directions).
330 #ifdef INET6
331 memset(&tha, 0, sizeof(tha));
332 rev = 0;
333 if (ip6) {
334 src = &ip6->ip6_src;
335 dst = &ip6->ip6_dst;
336 if (sport > dport)
337 rev = 1;
338 else if (sport == dport) {
339 if (memcmp(src, dst, sizeof ip6->ip6_dst) > 0)
340 rev = 1;
342 if (rev) {
343 memcpy(&tha.src, dst, sizeof ip6->ip6_dst);
344 memcpy(&tha.dst, src, sizeof ip6->ip6_src);
345 tha.port = dport << 16 | sport;
346 } else {
347 memcpy(&tha.dst, dst, sizeof ip6->ip6_dst);
348 memcpy(&tha.src, src, sizeof ip6->ip6_src);
349 tha.port = sport << 16 | dport;
351 } else {
352 src = &ip->ip_src;
353 dst = &ip->ip_dst;
354 if (sport > dport)
355 rev = 1;
356 else if (sport == dport) {
357 if (memcmp(src, dst, sizeof ip->ip_dst) > 0)
358 rev = 1;
360 if (rev) {
361 memcpy(&tha.src, dst, sizeof ip->ip_dst);
362 memcpy(&tha.dst, src, sizeof ip->ip_src);
363 tha.port = dport << 16 | sport;
364 } else {
365 memcpy(&tha.dst, dst, sizeof ip->ip_dst);
366 memcpy(&tha.src, src, sizeof ip->ip_src);
367 tha.port = sport << 16 | dport;
370 #else
371 rev = 0;
372 src = &ip->ip_src;
373 dst = &ip->ip_dst;
374 if (sport > dport)
375 rev = 1;
376 else if (sport == dport) {
377 if (memcmp(src, dst, sizeof ip->ip_dst) > 0)
378 rev = 1;
380 if (rev) {
381 memcpy(&tha.src, dst, sizeof ip->ip_dst);
382 memcpy(&tha.dst, src, sizeof ip->ip_src);
383 tha.port = dport << 16 | sport;
384 } else {
385 memcpy(&tha.dst, dst, sizeof ip->ip_dst);
386 memcpy(&tha.src, src, sizeof ip->ip_src);
387 tha.port = sport << 16 | dport;
389 #endif
391 threv = rev;
392 for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE];
393 th->nxt; th = th->nxt)
394 if (memcmp((char *)&tha, (char *)&th->addr,
395 sizeof(th->addr)) == 0)
396 break;
398 if (!th->nxt || (flags & TH_SYN)) {
399 /* didn't find it or new conversation */
400 if (th->nxt == NULL) {
401 th->nxt = (struct tcp_seq_hash *)
402 calloc(1, sizeof(*th));
403 if (th->nxt == NULL)
404 error("tcp_print: calloc");
406 th->addr = tha;
407 if (rev)
408 th->ack = seq, th->seq = ack - 1;
409 else
410 th->seq = seq, th->ack = ack - 1;
411 } else {
412 if (rev)
413 seq -= th->ack, ack -= th->seq;
414 else
415 seq -= th->seq, ack -= th->ack;
418 thseq = th->seq;
419 thack = th->ack;
420 } else {
421 /*fool gcc*/
422 thseq = thack = threv = 0;
424 if (hlen > length) {
425 (void)printf(" [bad hdr length %u - too long, > %u]",
426 hlen, length);
427 return;
430 if (IP_V(ip) == 4 && vflag && !fragmented) {
431 u_int16_t sum, tcp_sum;
432 if (TTEST2(tp->th_sport, length)) {
433 sum = tcp_cksum(ip, tp, length);
435 (void)printf(", cksum 0x%04x",EXTRACT_16BITS(&tp->th_sum));
436 if (sum != 0) {
437 tcp_sum = EXTRACT_16BITS(&tp->th_sum);
438 (void)printf(" (incorrect (-> 0x%04x),",in_cksum_shouldbe(tcp_sum, sum));
439 } else
440 (void)printf(" (correct),");
443 #ifdef INET6
444 if (IP_V(ip) == 6 && ip6->ip6_plen && vflag && !fragmented) {
445 u_int16_t sum,tcp_sum;
446 if (TTEST2(tp->th_sport, length)) {
447 sum = tcp6_cksum(ip6, tp, length);
448 (void)printf(", cksum 0x%04x",EXTRACT_16BITS(&tp->th_sum));
449 if (sum != 0) {
450 tcp_sum = EXTRACT_16BITS(&tp->th_sum);
451 (void)printf(" (incorrect (-> 0x%04x),",in_cksum_shouldbe(tcp_sum, sum));
452 } else
453 (void)printf(" (correct),");
457 #endif
459 length -= hlen;
460 if (vflag > 1 || length > 0 || flags & (TH_SYN | TH_FIN | TH_RST))
461 (void)printf(" %u:%u(%u)", seq, seq + length, length);
462 if (flags & TH_ACK)
463 (void)printf(" ack %u", ack);
465 (void)printf(" win %d", win);
467 if (flags & TH_URG)
468 (void)printf(" urg %d", urp);
470 * Handle any options.
472 if (hlen > sizeof(*tp)) {
473 register const u_char *cp;
474 register u_int i, opt, datalen;
475 register u_int len;
477 hlen -= sizeof(*tp);
478 cp = (const u_char *)tp + sizeof(*tp);
479 putchar(' ');
480 ch = '<';
481 while (hlen > 0) {
482 putchar(ch);
483 TCHECK(*cp);
484 opt = *cp++;
485 if (ZEROLENOPT(opt))
486 len = 1;
487 else {
488 TCHECK(*cp);
489 len = *cp++; /* total including type, len */
490 if (len < 2 || len > hlen)
491 goto bad;
492 --hlen; /* account for length byte */
494 --hlen; /* account for type byte */
495 datalen = 0;
497 /* Bail if "l" bytes of data are not left or were not captured */
498 #define LENCHECK(l) { if ((l) > hlen) goto bad; TCHECK2(*cp, l); }
500 switch (opt) {
502 case TCPOPT_MAXSEG:
503 (void)printf("mss");
504 datalen = 2;
505 LENCHECK(datalen);
506 (void)printf(" %u", EXTRACT_16BITS(cp));
508 break;
510 case TCPOPT_EOL:
511 (void)printf("eol");
512 break;
514 case TCPOPT_NOP:
515 (void)printf("nop");
516 break;
518 case TCPOPT_WSCALE:
519 (void)printf("wscale");
520 datalen = 1;
521 LENCHECK(datalen);
522 (void)printf(" %u", *cp);
523 break;
525 case TCPOPT_SACKOK:
526 (void)printf("sackOK");
527 break;
529 case TCPOPT_SACK:
530 datalen = len - 2;
531 if (datalen % 8 != 0) {
532 (void)printf("malformed sack");
533 } else {
534 u_int32_t s, e;
536 (void)printf("sack %d ", datalen / 8);
537 for (i = 0; i < datalen; i += 8) {
538 LENCHECK(i + 4);
539 s = EXTRACT_32BITS(cp + i);
540 LENCHECK(i + 8);
541 e = EXTRACT_32BITS(cp + i + 4);
542 if (threv) {
543 s -= thseq;
544 e -= thseq;
545 } else {
546 s -= thack;
547 e -= thack;
549 (void)printf("{%u:%u}", s, e);
552 break;
554 case TCPOPT_ECHO:
555 (void)printf("echo");
556 datalen = 4;
557 LENCHECK(datalen);
558 (void)printf(" %u", EXTRACT_32BITS(cp));
559 break;
561 case TCPOPT_ECHOREPLY:
562 (void)printf("echoreply");
563 datalen = 4;
564 LENCHECK(datalen);
565 (void)printf(" %u", EXTRACT_32BITS(cp));
566 break;
568 case TCPOPT_TIMESTAMP:
569 (void)printf("timestamp");
570 datalen = 8;
571 LENCHECK(4);
572 (void)printf(" %u", EXTRACT_32BITS(cp));
573 LENCHECK(datalen);
574 (void)printf(" %u", EXTRACT_32BITS(cp + 4));
575 break;
577 case TCPOPT_CC:
578 (void)printf("cc");
579 datalen = 4;
580 LENCHECK(datalen);
581 (void)printf(" %u", EXTRACT_32BITS(cp));
582 break;
584 case TCPOPT_CCNEW:
585 (void)printf("ccnew");
586 datalen = 4;
587 LENCHECK(datalen);
588 (void)printf(" %u", EXTRACT_32BITS(cp));
589 break;
591 case TCPOPT_CCECHO:
592 (void)printf("ccecho");
593 datalen = 4;
594 LENCHECK(datalen);
595 (void)printf(" %u", EXTRACT_32BITS(cp));
596 break;
598 case TCPOPT_SIGNATURE:
599 (void)printf("md5:");
600 datalen = TCP_SIGLEN;
601 LENCHECK(datalen);
602 #ifdef HAVE_LIBCRYPTO
603 switch (tcp_verify_signature(ip, tp,
604 bp + TH_OFF(tp) * 4, length, cp)) {
606 case SIGNATURE_VALID:
607 (void)printf("valid");
608 break;
610 case SIGNATURE_INVALID:
611 (void)printf("invalid");
612 break;
614 case CANT_CHECK_SIGNATURE:
615 (void)printf("can't check - ");
616 for (i = 0; i < TCP_SIGLEN; ++i)
617 (void)printf("%02x", cp[i]);
618 break;
620 #else
621 for (i = 0; i < TCP_SIGLEN; ++i)
622 (void)printf("%02x", cp[i]);
623 #endif
624 break;
626 default:
627 (void)printf("opt-%u:", opt);
628 datalen = len - 2;
629 for (i = 0; i < datalen; ++i) {
630 LENCHECK(i);
631 (void)printf("%02x", cp[i]);
633 break;
636 /* Account for data printed */
637 cp += datalen;
638 hlen -= datalen;
640 /* Check specification against observed length */
641 ++datalen; /* option octet */
642 if (!ZEROLENOPT(opt))
643 ++datalen; /* size octet */
644 if (datalen != len)
645 (void)printf("[len %d]", len);
646 ch = ',';
647 if (opt == TCPOPT_EOL)
648 break;
650 putchar('>');
653 if (length <= 0)
654 return;
657 * Decode payload if necessary.
659 bp += TH_OFF(tp) * 4;
660 if (flags & TH_RST) {
661 if (vflag)
662 print_tcp_rst_data(bp, length);
663 } else {
664 if (sport == TELNET_PORT || dport == TELNET_PORT) {
665 if (!qflag && vflag)
666 telnet_print(bp, length);
667 } else if (sport == BGP_PORT || dport == BGP_PORT)
668 bgp_print(bp, length);
669 else if (sport == PPTP_PORT || dport == PPTP_PORT)
670 pptp_print(bp);
671 #ifdef TCPDUMP_DO_SMB
672 else if (sport == NETBIOS_SSN_PORT || dport == NETBIOS_SSN_PORT)
673 nbt_tcp_print(bp, length);
674 #endif
675 else if (sport == BEEP_PORT || dport == BEEP_PORT)
676 beep_print(bp, length);
677 else if (length > 2 &&
678 (sport == NAMESERVER_PORT || dport == NAMESERVER_PORT ||
679 sport == MULTICASTDNS_PORT || dport == MULTICASTDNS_PORT)) {
681 * TCP DNS query has 2byte length at the head.
682 * XXX packet could be unaligned, it can go strange
684 ns_print(bp + 2, length - 2, 0);
685 } else if (sport == MSDP_PORT || dport == MSDP_PORT) {
686 msdp_print(bp, length);
688 else if (length > 0 && (sport == LDP_PORT || dport == LDP_PORT)) {
689 ldp_print(bp, length);
692 return;
693 bad:
694 fputs("[bad opt]", stdout);
695 if (ch != '\0')
696 putchar('>');
697 return;
698 trunc:
699 fputs("[|tcp]", stdout);
700 if (ch != '\0')
701 putchar('>');
705 * RFC1122 says the following on data in RST segments:
707 * 4.2.2.12 RST Segment: RFC-793 Section 3.4
709 * A TCP SHOULD allow a received RST segment to include data.
711 * DISCUSSION
712 * It has been suggested that a RST segment could contain
713 * ASCII text that encoded and explained the cause of the
714 * RST. No standard has yet been established for such
715 * data.
719 static void
720 print_tcp_rst_data(register const u_char *sp, u_int length)
722 int c;
724 if (TTEST2(*sp, length))
725 printf(" [RST");
726 else
727 printf(" [!RST");
728 if (length > MAX_RST_DATA_LEN) {
729 length = MAX_RST_DATA_LEN; /* can use -X for longer */
730 putchar('+'); /* indicate we truncate */
732 putchar(' ');
733 while (length-- && sp <= snapend) {
734 c = *sp++;
735 safeputchar(c);
737 putchar(']');
740 #ifdef HAVE_LIBCRYPTO
741 static int
742 tcp_verify_signature(const struct ip *ip, const struct tcphdr *tp,
743 const u_char *data, int length, const u_char *rcvsig)
745 struct tcphdr tp1;
746 u_char sig[TCP_SIGLEN];
747 char zero_proto = 0;
748 MD5_CTX ctx;
749 u_int16_t savecsum, tlen;
750 #ifdef INET6
751 struct ip6_hdr *ip6;
752 u_int32_t len32;
753 u_int8_t nxt;
754 #endif
756 tp1 = *tp;
758 if (tcpmd5secret == NULL)
759 return (CANT_CHECK_SIGNATURE);
761 MD5_Init(&ctx);
763 * Step 1: Update MD5 hash with IP pseudo-header.
765 if (IP_V(ip) == 4) {
766 MD5_Update(&ctx, (char *)&ip->ip_src, sizeof(ip->ip_src));
767 MD5_Update(&ctx, (char *)&ip->ip_dst, sizeof(ip->ip_dst));
768 MD5_Update(&ctx, (char *)&zero_proto, sizeof(zero_proto));
769 MD5_Update(&ctx, (char *)&ip->ip_p, sizeof(ip->ip_p));
770 tlen = EXTRACT_16BITS(&ip->ip_len) - IP_HL(ip) * 4;
771 tlen = htons(tlen);
772 MD5_Update(&ctx, (char *)&tlen, sizeof(tlen));
773 #ifdef INET6
774 } else if (IP_V(ip) == 6) {
775 ip6 = (struct ip6_hdr *)ip;
776 MD5_Update(&ctx, (char *)&ip6->ip6_src, sizeof(ip6->ip6_src));
777 MD5_Update(&ctx, (char *)&ip6->ip6_dst, sizeof(ip6->ip6_dst));
778 len32 = htonl(ntohs(ip6->ip6_plen));
779 MD5_Update(&ctx, (char *)&len32, sizeof(len32));
780 nxt = 0;
781 MD5_Update(&ctx, (char *)&nxt, sizeof(nxt));
782 MD5_Update(&ctx, (char *)&nxt, sizeof(nxt));
783 MD5_Update(&ctx, (char *)&nxt, sizeof(nxt));
784 nxt = IPPROTO_TCP;
785 MD5_Update(&ctx, (char *)&nxt, sizeof(nxt));
786 #endif
787 } else
788 return (CANT_CHECK_SIGNATURE);
791 * Step 2: Update MD5 hash with TCP header, excluding options.
792 * The TCP checksum must be set to zero.
794 savecsum = tp1.th_sum;
795 tp1.th_sum = 0;
796 MD5_Update(&ctx, (char *)&tp1, sizeof(struct tcphdr));
797 tp1.th_sum = savecsum;
799 * Step 3: Update MD5 hash with TCP segment data, if present.
801 if (length > 0)
802 MD5_Update(&ctx, data, length);
804 * Step 4: Update MD5 hash with shared secret.
806 MD5_Update(&ctx, tcpmd5secret, strlen(tcpmd5secret));
807 MD5_Final(sig, &ctx);
809 if (memcmp(rcvsig, sig, TCP_SIGLEN) == 0)
810 return (SIGNATURE_VALID);
811 else
812 return (SIGNATURE_INVALID);
814 #endif /* HAVE_LIBCRYPTO */