print-dccp.c revision 214478
1162017Ssam/*
2162017Ssam * Copyright (C) Arnaldo Carvalho de Melo 2004
3162017Ssam * Copyright (C) Ian McDonald 2005
4162017Ssam * Copyright (C) Yoshifumi Nishida 2005
5162017Ssam *
6162017Ssam * This software may be distributed either under the terms of the
7162017Ssam * BSD-style license that accompanies tcpdump or the GNU GPL version 2
8162017Ssam */
9162017Ssam
10162017Ssam#ifndef lint
11162017Ssamstatic const char rcsid[] _U_ =
12214478Srpaulo    "@(#) $Header: /tcpdump/master/tcpdump/print-dccp.c,v 1.8 2007-11-09 00:44:09 guy Exp $ (LBL)";
13162017Ssam#endif
14162017Ssam
15162017Ssam#ifdef HAVE_CONFIG_H
16162017Ssam#include "config.h"
17162017Ssam#endif
18162017Ssam
19162017Ssam#include <tcpdump-stdinc.h>
20162017Ssam
21162017Ssam#include "dccp.h"
22162017Ssam
23162017Ssam#include <stdio.h>
24162017Ssam#include <string.h>
25162017Ssam
26162017Ssam#include "interface.h"
27162017Ssam#include "addrtoname.h"
28162017Ssam#include "extract.h"			/* must come after interface.h */
29162017Ssam#include "ip.h"
30162017Ssam#ifdef INET6
31162017Ssam#include "ip6.h"
32162017Ssam#endif
33162017Ssam#include "ipproto.h"
34162017Ssam
35162017Ssamstatic const char *dccp_reset_codes[] = {
36162017Ssam	"unspecified",
37162017Ssam	"closed",
38162017Ssam	"aborted",
39162017Ssam	"no_connection",
40162017Ssam	"packet_error",
41162017Ssam	"option_error",
42162017Ssam	"mandatory_error",
43162017Ssam	"connection_refused",
44162017Ssam	"bad_service_code",
45162017Ssam	"too_busy",
46162017Ssam	"bad_init_cookie",
47162017Ssam	"aggression_penalty",
48162017Ssam};
49162017Ssam
50162017Ssamstatic const char *dccp_feature_nums[] = {
51162017Ssam	"reserved",
52162017Ssam	"ccid",
53162017Ssam	"allow_short_seqno",
54162017Ssam	"sequence_window",
55162017Ssam	"ecn_incapable",
56162017Ssam	"ack_ratio",
57162017Ssam	"send_ack_vector",
58162017Ssam	"send_ndp_count",
59162017Ssam	"minimum checksum coverage",
60162017Ssam	"check data checksum",
61162017Ssam};
62162017Ssam
63190207Srpaulostatic inline int dccp_csum_coverage(const struct dccp_hdr* dh, u_int len)
64190207Srpaulo{
65190207Srpaulo	u_int cov;
66190207Srpaulo
67190207Srpaulo	if (DCCPH_CSCOV(dh) == 0)
68190207Srpaulo		return len;
69190207Srpaulo	cov = (dh->dccph_doff + DCCPH_CSCOV(dh) - 1) * sizeof(u_int32_t);
70190207Srpaulo	return (cov > len)? len : cov;
71190207Srpaulo}
72190207Srpaulo
73162017Ssamstatic int dccp_cksum(const struct ip *ip,
74162017Ssam	const struct dccp_hdr *dh, u_int len)
75162017Ssam{
76190207Srpaulo	int cov = dccp_csum_coverage(dh, len);
77162017Ssam	union phu {
78162017Ssam		struct phdr {
79162017Ssam			u_int32_t src;
80162017Ssam			u_int32_t dst;
81162017Ssam			u_char mbz;
82162017Ssam			u_char proto;
83162017Ssam			u_int16_t len;
84162017Ssam		} ph;
85162017Ssam		u_int16_t pa[6];
86162017Ssam	} phu;
87162017Ssam	const u_int16_t *sp;
88162017Ssam
89162017Ssam	/* pseudo-header.. */
90162017Ssam	phu.ph.mbz = 0;
91162017Ssam	phu.ph.len = htons(len);
92162017Ssam	phu.ph.proto = IPPROTO_DCCP;
93162017Ssam	memcpy(&phu.ph.src, &ip->ip_src.s_addr, sizeof(u_int32_t));
94162017Ssam	if (IP_HL(ip) == 5)
95162017Ssam		memcpy(&phu.ph.dst, &ip->ip_dst.s_addr, sizeof(u_int32_t));
96162017Ssam	else
97162017Ssam		phu.ph.dst = ip_finddst(ip);
98162017Ssam
99162017Ssam	sp = &phu.pa[0];
100190207Srpaulo	return in_cksum((u_short *)dh, cov, sp[0]+sp[1]+sp[2]+sp[3]+sp[4]+sp[5]);
101162017Ssam}
102162017Ssam
103162017Ssam#ifdef INET6
104162017Ssamstatic int dccp6_cksum(const struct ip6_hdr *ip6, const struct dccp_hdr *dh, u_int len)
105162017Ssam{
106162017Ssam	size_t i;
107190207Srpaulo	u_int32_t sum = 0;
108190207Srpaulo	int cov = dccp_csum_coverage(dh, len);
109162017Ssam	union {
110162017Ssam		struct {
111162017Ssam			struct in6_addr ph_src;
112162017Ssam			struct in6_addr ph_dst;
113162017Ssam			u_int32_t   ph_len;
114162017Ssam			u_int8_t    ph_zero[3];
115162017Ssam			u_int8_t    ph_nxt;
116162017Ssam		} ph;
117162017Ssam		u_int16_t pa[20];
118162017Ssam	} phu;
119162017Ssam
120162017Ssam	/* pseudo-header */
121162017Ssam	memset(&phu, 0, sizeof(phu));
122162017Ssam	phu.ph.ph_src = ip6->ip6_src;
123162017Ssam	phu.ph.ph_dst = ip6->ip6_dst;
124162017Ssam	phu.ph.ph_len = htonl(len);
125162017Ssam	phu.ph.ph_nxt = IPPROTO_DCCP;
126162017Ssam
127162017Ssam	for (i = 0; i < sizeof(phu.pa) / sizeof(phu.pa[0]); i++)
128162017Ssam		sum += phu.pa[i];
129162017Ssam
130190207Srpaulo	return in_cksum((u_short *)dh, cov, sum);
131162017Ssam}
132162017Ssam#endif
133162017Ssam
134162017Ssamstatic const char *dccp_reset_code(u_int8_t code)
135162017Ssam{
136162017Ssam	if (code >= __DCCP_RESET_CODE_LAST)
137162017Ssam		return "invalid";
138162017Ssam	return dccp_reset_codes[code];
139162017Ssam}
140162017Ssam
141162017Ssamstatic u_int64_t dccp_seqno(const struct dccp_hdr *dh)
142162017Ssam{
143162017Ssam	u_int32_t seq_high = DCCPH_SEQ(dh);
144162017Ssam	u_int64_t seqno = EXTRACT_24BITS(&seq_high) & 0xFFFFFF;
145162017Ssam
146162017Ssam	if (DCCPH_X(dh) != 0) {
147172683Smlaier		const struct dccp_hdr_ext *dhx = (void *)(dh + 1);
148162017Ssam		u_int32_t seq_low = dhx->dccph_seq_low;
149162017Ssam		seqno &= 0x00FFFF;  /* clear reserved field */
150162017Ssam		seqno = (seqno << 32) + EXTRACT_32BITS(&seq_low);
151162017Ssam	}
152162017Ssam
153162017Ssam	return seqno;
154162017Ssam}
155162017Ssam
156172683Smlaierstatic inline unsigned int dccp_basic_hdr_len(const struct dccp_hdr *dh)
157162017Ssam{
158172683Smlaier	return sizeof(*dh) + (DCCPH_X(dh) ? sizeof(struct dccp_hdr_ext) : 0);
159172683Smlaier}
160162017Ssam
161172683Smlaierstatic void dccp_print_ack_no(const u_char *bp)
162172683Smlaier{
163172683Smlaier	const struct dccp_hdr *dh = (const struct dccp_hdr *)bp;
164172683Smlaier	const struct dccp_hdr_ack_bits *dh_ack =
165172683Smlaier		(struct dccp_hdr_ack_bits *)(bp + dccp_basic_hdr_len(dh));
166172683Smlaier	u_int32_t ack_high;
167172683Smlaier	u_int64_t ackno;
168172683Smlaier
169172683Smlaier	TCHECK2(*dh_ack,4);
170172683Smlaier	ack_high = DCCPH_ACK(dh_ack);
171172683Smlaier	ackno = EXTRACT_24BITS(&ack_high) & 0xFFFFFF;
172172683Smlaier
173162017Ssam	if (DCCPH_X(dh) != 0) {
174172683Smlaier		u_int32_t ack_low;
175172683Smlaier
176172683Smlaier		TCHECK2(*dh_ack,8);
177172683Smlaier		ack_low = dh_ack->dccph_ack_nr_low;
178172683Smlaier
179162017Ssam		ackno &= 0x00FFFF;  /* clear reserved field */
180162017Ssam		ackno = (ackno << 32) + EXTRACT_32BITS(&ack_low);
181162017Ssam	}
182162017Ssam
183172683Smlaier	(void)printf("(ack=%" PRIu64 ") ", ackno);
184172683Smlaiertrunc:
185172683Smlaier	return;
186162017Ssam}
187162017Ssam
188162017Ssamstatic inline unsigned int dccp_packet_hdr_len(const u_int8_t type)
189162017Ssam{
190162017Ssam	if (type == DCCP_PKT_DATA)
191162017Ssam		return 0;
192162017Ssam	if (type == DCCP_PKT_DATAACK	||
193162017Ssam	    type == DCCP_PKT_ACK	||
194162017Ssam	    type == DCCP_PKT_SYNC	||
195162017Ssam	    type == DCCP_PKT_SYNCACK	||
196162017Ssam	    type == DCCP_PKT_CLOSE	||
197162017Ssam	    type == DCCP_PKT_CLOSEREQ)
198162017Ssam		return sizeof(struct dccp_hdr_ack_bits);
199162017Ssam	if (type == DCCP_PKT_REQUEST)
200162017Ssam		return sizeof(struct dccp_hdr_request);
201162017Ssam	if (type == DCCP_PKT_RESPONSE)
202162017Ssam		return sizeof(struct dccp_hdr_response);
203162017Ssam	return sizeof(struct dccp_hdr_reset);
204162017Ssam}
205162017Ssam
206162017Ssamstatic int dccp_print_option(const u_char *option);
207162017Ssam
208162017Ssam/**
209162017Ssam * dccp_print - show dccp packet
210162017Ssam * @bp - beginning of dccp packet
211162017Ssam * @data2 - beginning of enclosing
212162017Ssam * @len - lenght of ip packet
213162017Ssam */
214162017Ssamvoid dccp_print(const u_char *bp, const u_char *data2, u_int len)
215162017Ssam{
216162017Ssam	const struct dccp_hdr *dh;
217162017Ssam	const struct ip *ip;
218162017Ssam#ifdef INET6
219162017Ssam	const struct ip6_hdr *ip6;
220162017Ssam#endif
221162017Ssam	const u_char *cp;
222162017Ssam	u_short sport, dport;
223162017Ssam	u_int hlen;
224162017Ssam	u_int extlen = 0;
225162017Ssam
226162017Ssam	dh = (const struct dccp_hdr *)bp;
227162017Ssam
228162017Ssam	ip = (struct ip *)data2;
229162017Ssam#ifdef INET6
230162017Ssam	if (IP_V(ip) == 6)
231162017Ssam		ip6 = (const struct ip6_hdr *)data2;
232162017Ssam	else
233162017Ssam		ip6 = NULL;
234162017Ssam#endif /*INET6*/
235162017Ssam	cp = (const u_char *)(dh + 1);
236162017Ssam	if (cp > snapend) {
237162017Ssam		printf("[Invalid packet|dccp]");
238162017Ssam		return;
239162017Ssam	}
240162017Ssam
241162017Ssam	if (len < sizeof(struct dccp_hdr)) {
242162017Ssam		printf("truncated-dccp - %ld bytes missing!",
243162017Ssam			     (long)len - sizeof(struct dccp_hdr));
244162017Ssam		return;
245162017Ssam	}
246162017Ssam
247162017Ssam	sport = EXTRACT_16BITS(&dh->dccph_sport);
248162017Ssam	dport = EXTRACT_16BITS(&dh->dccph_dport);
249162017Ssam	hlen = dh->dccph_doff * 4;
250162017Ssam
251162017Ssam#ifdef INET6
252162017Ssam	if (ip6) {
253162017Ssam		(void)printf("%s.%d > %s.%d: ",
254162017Ssam			     ip6addr_string(&ip6->ip6_src), sport,
255162017Ssam			     ip6addr_string(&ip6->ip6_dst), dport);
256162017Ssam	} else
257162017Ssam#endif /*INET6*/
258162017Ssam	{
259162017Ssam		(void)printf("%s.%d > %s.%d: ",
260162017Ssam			     ipaddr_string(&ip->ip_src), sport,
261162017Ssam			     ipaddr_string(&ip->ip_dst), dport);
262162017Ssam	}
263162017Ssam	fflush(stdout);
264162017Ssam
265162017Ssam	if (qflag) {
266162017Ssam		(void)printf(" %d", len - hlen);
267162017Ssam		if (hlen > len) {
268162017Ssam			(void)printf("dccp [bad hdr length %u - too long, > %u]",
269162017Ssam			    hlen, len);
270162017Ssam		}
271162017Ssam		return;
272162017Ssam	}
273162017Ssam
274162017Ssam	/* other variables in generic header */
275162017Ssam	if (vflag) {
276162017Ssam		(void)printf("CCVal %d, CsCov %d, ", DCCPH_CCVAL(dh), DCCPH_CSCOV(dh));
277162017Ssam	}
278162017Ssam
279162017Ssam	/* checksum calculation */
280190207Srpaulo	if (vflag && TTEST2(bp[0], len)) {
281190207Srpaulo		u_int16_t sum = 0, dccp_sum;
282190207Srpaulo
283190207Srpaulo		dccp_sum = EXTRACT_16BITS(&dh->dccph_checksum);
284190207Srpaulo		(void)printf("cksum 0x%04x ", dccp_sum);
285190207Srpaulo		if (IP_V(ip) == 4)
286190207Srpaulo			sum = dccp_cksum(ip, dh, len);
287162017Ssam#ifdef INET6
288190207Srpaulo		else if (IP_V(ip) == 6)
289162017Ssam			sum = dccp6_cksum(ip6, dh, len);
290190207Srpaulo#endif
291190207Srpaulo		if (sum != 0)
292190207Srpaulo			(void)printf("(incorrect -> 0x%04x), ",in_cksum_shouldbe(dccp_sum, sum));
293190207Srpaulo		else
294190207Srpaulo			(void)printf("(correct), ");
295162017Ssam	}
296162017Ssam
297162017Ssam	switch (DCCPH_TYPE(dh)) {
298162017Ssam	case DCCP_PKT_REQUEST: {
299162017Ssam		struct dccp_hdr_request *dhr =
300162017Ssam			(struct dccp_hdr_request *)(bp + dccp_basic_hdr_len(dh));
301162017Ssam		TCHECK(*dhr);
302172683Smlaier		(void)printf("request (service=%d) ",
303172683Smlaier			     EXTRACT_32BITS(&dhr->dccph_req_service));
304162017Ssam		extlen += 4;
305162017Ssam		break;
306162017Ssam	}
307162017Ssam	case DCCP_PKT_RESPONSE: {
308162017Ssam		struct dccp_hdr_response *dhr =
309162017Ssam			(struct dccp_hdr_response *)(bp + dccp_basic_hdr_len(dh));
310162017Ssam		TCHECK(*dhr);
311172683Smlaier		(void)printf("response (service=%d) ",
312172683Smlaier			     EXTRACT_32BITS(&dhr->dccph_resp_service));
313162017Ssam		extlen += 12;
314162017Ssam		break;
315162017Ssam	}
316162017Ssam	case DCCP_PKT_DATA:
317162017Ssam		(void)printf("data ");
318162017Ssam		break;
319162017Ssam	case DCCP_PKT_ACK: {
320172683Smlaier		(void)printf("ack ");
321162017Ssam		extlen += 8;
322162017Ssam		break;
323162017Ssam	}
324162017Ssam	case DCCP_PKT_DATAACK: {
325172683Smlaier		(void)printf("dataack ");
326162017Ssam		extlen += 8;
327162017Ssam		break;
328162017Ssam	}
329162017Ssam	case DCCP_PKT_CLOSEREQ:
330162017Ssam		(void)printf("closereq ");
331162017Ssam		extlen += 8;
332162017Ssam		break;
333162017Ssam	case DCCP_PKT_CLOSE:
334162017Ssam		(void)printf("close ");
335162017Ssam		extlen += 8;
336162017Ssam		break;
337162017Ssam	case DCCP_PKT_RESET: {
338162017Ssam		struct dccp_hdr_reset *dhr =
339162017Ssam			(struct dccp_hdr_reset *)(bp + dccp_basic_hdr_len(dh));
340162017Ssam		TCHECK(*dhr);
341162017Ssam		(void)printf("reset (code=%s) ",
342162017Ssam			     dccp_reset_code(dhr->dccph_reset_code));
343162017Ssam		extlen += 12;
344162017Ssam		break;
345162017Ssam	}
346162017Ssam	case DCCP_PKT_SYNC:
347162017Ssam		(void)printf("sync ");
348162017Ssam		extlen += 8;
349162017Ssam		break;
350162017Ssam	case DCCP_PKT_SYNCACK:
351162017Ssam		(void)printf("syncack ");
352162017Ssam		extlen += 8;
353162017Ssam		break;
354162017Ssam	default:
355162017Ssam		(void)printf("invalid ");
356162017Ssam		break;
357162017Ssam	}
358162017Ssam
359172683Smlaier	if ((DCCPH_TYPE(dh) != DCCP_PKT_DATA) &&
360172683Smlaier			(DCCPH_TYPE(dh) != DCCP_PKT_REQUEST))
361172683Smlaier		dccp_print_ack_no(bp);
362172683Smlaier
363162017Ssam	if (vflag < 2)
364162017Ssam		return;
365162017Ssam
366162017Ssam	(void)printf("seq %" PRIu64, dccp_seqno(dh));
367162017Ssam
368162017Ssam	/* process options */
369162017Ssam	if (hlen > dccp_basic_hdr_len(dh) + extlen){
370162017Ssam		const u_char *cp;
371162017Ssam		u_int optlen;
372162017Ssam		cp = bp + dccp_basic_hdr_len(dh) + extlen;
373162017Ssam		printf(" <");
374162017Ssam
375162017Ssam		hlen -= dccp_basic_hdr_len(dh) + extlen;
376162017Ssam		while(1){
377162017Ssam			TCHECK(*cp);
378162017Ssam			optlen = dccp_print_option(cp);
379162017Ssam			if (!optlen) goto trunc2;
380162017Ssam			if (hlen <= optlen) break;
381162017Ssam			hlen -= optlen;
382162017Ssam			cp += optlen;
383162017Ssam			printf(", ");
384162017Ssam		}
385162017Ssam		printf(">");
386162017Ssam	}
387162017Ssam	return;
388162017Ssamtrunc:
389162017Ssam	printf("[|dccp]");
390162017Ssamtrunc2:
391162017Ssam	return;
392162017Ssam}
393162017Ssam
394162017Ssamstatic int dccp_print_option(const u_char *option)
395162017Ssam{
396162017Ssam	u_int8_t optlen, i;
397162017Ssam
398162017Ssam	TCHECK(*option);
399162017Ssam
400162017Ssam	if (*option >= 32) {
401162017Ssam		TCHECK(*(option+1));
402162017Ssam		optlen = *(option +1);
403162017Ssam		if (optlen < 2) {
404162017Ssam			printf("Option %d optlen too short",*option);
405162017Ssam			return 1;
406162017Ssam		}
407162017Ssam	} else optlen = 1;
408162017Ssam
409162017Ssam	TCHECK2(*option,optlen);
410162017Ssam
411162017Ssam	switch (*option){
412162017Ssam	case 0:
413162017Ssam		printf("nop");
414162017Ssam		break;
415162017Ssam	case 1:
416162017Ssam		printf("mandatory");
417162017Ssam		break;
418162017Ssam	case 2:
419162017Ssam		printf("slowreceiver");
420162017Ssam		break;
421162017Ssam	case 32:
422162017Ssam		printf("change_l");
423162017Ssam		if (*(option +2) < 10){
424162017Ssam			printf(" %s", dccp_feature_nums[*(option +2)]);
425162017Ssam			for (i = 0; i < optlen -3; i ++) printf(" %d", *(option +3 + i));
426162017Ssam		}
427162017Ssam		break;
428162017Ssam	case 33:
429162017Ssam		printf("confirm_l");
430162017Ssam		if (*(option +2) < 10){
431162017Ssam			printf(" %s", dccp_feature_nums[*(option +2)]);
432162017Ssam			for (i = 0; i < optlen -3; i ++) printf(" %d", *(option +3 + i));
433162017Ssam		}
434162017Ssam		break;
435162017Ssam	case 34:
436162017Ssam	        printf("change_r");
437162017Ssam		if (*(option +2) < 10){
438162017Ssam			printf(" %s", dccp_feature_nums[*(option +2)]);
439162017Ssam			for (i = 0; i < optlen -3; i ++) printf(" %d", *(option +3 + i));
440162017Ssam		}
441162017Ssam		break;
442162017Ssam	case 35:
443162017Ssam		printf("confirm_r");
444162017Ssam		if (*(option +2) < 10){
445162017Ssam			printf(" %s", dccp_feature_nums[*(option +2)]);
446162017Ssam			for (i = 0; i < optlen -3; i ++) printf(" %d", *(option +3 + i));
447162017Ssam		}
448162017Ssam		break;
449162017Ssam	case 36:
450162017Ssam		printf("initcookie 0x");
451162017Ssam		for (i = 0; i < optlen -2; i ++) printf("%02x", *(option +2 + i));
452162017Ssam		break;
453162017Ssam	case 37:
454162017Ssam		printf("ndp_count");
455162017Ssam		for (i = 0; i < optlen -2; i ++) printf(" %d", *(option +2 + i));
456162017Ssam		break;
457162017Ssam	case 38:
458162017Ssam		printf("ack_vector0 0x");
459162017Ssam		for (i = 0; i < optlen -2; i ++) printf("%02x", *(option +2 + i));
460162017Ssam		break;
461162017Ssam	case 39:
462162017Ssam		printf("ack_vector1 0x");
463162017Ssam		for (i = 0; i < optlen -2; i ++) printf("%02x", *(option +2 + i));
464162017Ssam		break;
465162017Ssam	case 40:
466162017Ssam		printf("data_dropped 0x");
467162017Ssam		for (i = 0; i < optlen -2; i ++) printf("%02x", *(option +2 + i));
468162017Ssam		break;
469162017Ssam	case 41:
470214478Srpaulo		printf("timestamp %u", EXTRACT_32BITS(option + 2));
471162017Ssam		break;
472162017Ssam	case 42:
473214478Srpaulo		printf("timestamp_echo %u", EXTRACT_32BITS(option + 2));
474162017Ssam		break;
475162017Ssam	case 43:
476162017Ssam		printf("elapsed_time ");
477214478Srpaulo		if (optlen == 6)
478214478Srpaulo			printf("%u", EXTRACT_32BITS(option + 2));
479214478Srpaulo		else
480214478Srpaulo			printf("%u", EXTRACT_16BITS(option + 2));
481162017Ssam		break;
482162017Ssam	case 44:
483162017Ssam		printf("data_checksum ");
484162017Ssam		for (i = 0; i < optlen -2; i ++) printf("%02x", *(option +2 + i));
485162017Ssam		break;
486162017Ssam	default :
487162017Ssam		if (*option >= 128) {
488162017Ssam			printf("CCID option %d",*option);
489162017Ssam			switch (optlen) {
490162017Ssam				case 4:
491214478Srpaulo					printf(" %u", EXTRACT_16BITS(option + 2));
492162017Ssam					break;
493162017Ssam				case 6:
494214478Srpaulo					printf(" %u", EXTRACT_32BITS(option + 2));
495162017Ssam					break;
496162017Ssam				default:
497162017Ssam					break;
498162017Ssam			}
499162017Ssam			break;
500162017Ssam		}
501162017Ssam
502162017Ssam		printf("unknown_opt %d", *option);
503162017Ssam		break;
504162017Ssam	}
505162017Ssam
506162017Ssam	return optlen;
507162017Ssamtrunc:
508162017Ssam	printf("[|dccp]");
509162017Ssam	return 0;
510162017Ssam}
511