1 /*
2  * mod_print.c
3  *
4  * Copyright (c) 2001 Dug Song <dugsong@monkey.org>
5  *
6  * $Id: mod_print.c,v 1.7 2002/04/07 22:55:20 dugsong Exp $
7  */
8 
9 #include "config.h"
10 
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 
15 #include "mod.h"
16 #include "pkt.h"
17 
18 #define EXTRACT_16BITS(p)	((uint16_t)ntohs(*(uint16_t *)(p)))
19 #define EXTRACT_32BITS(p)	((uint32_t)ntohl(*(uint32_t *)(p)))
20 
21 /* XXX - _print_* routines adapted from tcpdump */
22 
23 static void
_print_icmp(u_char * p,int length)24 _print_icmp(u_char *p, int length)
25 {
26 	struct ip_hdr *ip;
27 	struct icmp_hdr *icmp;
28 
29 	ip = (struct ip_hdr *)p;
30 	icmp = (struct icmp_hdr *)(p + (ip->ip_hl * 4));
31 
32 	/* XXX - truncation? */
33 	printf("%s > %s:", ip_ntoa(&ip->ip_src), ip_ntoa(&ip->ip_dst));
34 	printf(" icmp: type %d code %d", icmp->icmp_type, icmp->icmp_code);
35 }
36 
37 void
_print_tcp(unsigned char * p,int length)38 _print_tcp(unsigned char *p, int length)
39 {
40 	struct ip_hdr *ip;
41 	struct tcp_hdr *tcp;
42 	u_short sport, dport, win, urp;
43 	u_long seq, ack;
44 	int len, tcp_hl;
45 	register char ch;
46 
47 	ip = (struct ip_hdr *)p;
48 	tcp = (struct tcp_hdr *)(p + (ip->ip_hl * 4));
49 	len = length - (ip->ip_hl * 4);
50 
51 	if (len < TCP_HDR_LEN) {
52 		printf("truncated-tcp %d", len);
53 		return;
54 	}
55 	sport = ntohs(tcp->th_sport);
56 	dport = ntohs(tcp->th_dport);
57 	seq = ntohl(tcp->th_seq);
58 	ack = ntohl(tcp->th_ack);
59 	win = ntohs(tcp->th_win);
60 	urp = ntohs(tcp->th_urp);
61 	tcp_hl = tcp->th_off * 4;
62 
63 	printf("%s.%d > %s.%d: ", ip_ntoa(&ip->ip_src), sport,
64 	    ip_ntoa(&ip->ip_dst), dport);
65 
66 	if (tcp->th_flags & (TH_SYN|TH_FIN|TH_RST|TH_PUSH)) {
67 		if (tcp->th_flags & TH_SYN)	putchar('S');
68 		if (tcp->th_flags & TH_FIN)	putchar('F');
69 		if (tcp->th_flags & TH_RST)	putchar('R');
70 		if (tcp->th_flags & TH_PUSH)	putchar('P');
71 	} else
72 		putchar('.');
73 
74 	if (tcp_hl > len) {
75 		printf(" [bad hdr length]");
76 		return;
77 	}
78 	len -= tcp_hl;
79 
80 	if (len > 0 || tcp->th_flags & (TH_SYN | TH_FIN | TH_RST))
81 		printf(" %lu:%lu(%d)", seq, seq + len, len);
82 
83 	if (tcp->th_flags & TH_ACK)
84 		printf(" ack %lu", ack);
85 	printf(" win %d", win);
86 	if (tcp->th_flags & TH_URG)
87 		printf(" urg %d", urp);
88 
89 	/* Handle options. */
90 	if ((tcp_hl -= TCP_HDR_LEN) > 0) {
91 		register const u_char *cp;
92 		register int i, opt, len, datalen;
93 
94 		cp = (const u_char *)tcp + TCP_HDR_LEN;
95 		putchar(' ');
96 		ch = '<';
97 
98 		while (tcp_hl > 0) {
99 			putchar(ch);
100 			opt = *cp++;
101 			if (TCP_OPT_TYPEONLY(opt)) {
102 				len = 1;
103 			} else {
104 				len = *cp++;    /* total including type, len */
105 				if (len < 2 || len > tcp_hl)
106 					goto bad;
107 				--tcp_hl;         /* account for length byte */
108 			}
109 			--tcp_hl;           /* account for type byte */
110 			datalen = 0;
111 
112 /* Bail if "l" bytes of data are not left or were not captured  */
113 #define LENCHECK(l) { if ((l) > tcp_hl) goto bad; }
114 
115 			switch (opt) {
116 			case TCP_OPT_MSS:
117 				printf("mss");
118 				datalen = 2;
119 				LENCHECK(datalen);
120 				printf(" %u", EXTRACT_16BITS(cp));
121 				break;
122 			case TCP_OPT_EOL:
123 				printf("eol");
124 				break;
125 			case TCP_OPT_NOP:
126 				printf("nop");
127 				break;
128 			case TCP_OPT_WSCALE:
129 				printf("wscale");
130 				datalen = 1;
131 				LENCHECK(datalen);
132 				printf(" %u", *cp);
133 				break;
134 			case TCP_OPT_SACKOK:
135 				printf("sackOK");
136 				if (len != 2)
137 					printf("[len %d]", len);
138 				break;
139 			case TCP_OPT_SACK:
140 				datalen = len - 2;
141 				if ((datalen % 8) != 0 ||
142 				    !(tcp->th_flags & TH_ACK)) {
143 					printf("malformed sack ");
144 					printf("[len %d] ", datalen);
145 					break;
146 				}
147 				printf("sack %d ", datalen / 8);
148 				break;
149 			case TCP_OPT_ECHO:
150 				printf("echo");
151 				datalen = 4;
152 				LENCHECK(datalen);
153 				printf(" %u", EXTRACT_32BITS(cp));
154 				break;
155 			case TCP_OPT_ECHOREPLY:
156 				printf("echoreply");
157 				datalen = 4;
158 				LENCHECK(datalen);
159 				printf(" %u", EXTRACT_32BITS(cp));
160 				break;
161 			case TCP_OPT_TIMESTAMP:
162 				printf("timestamp");
163 				datalen = 8;
164 				LENCHECK(4);
165 				printf(" %u", EXTRACT_32BITS(cp));
166 				LENCHECK(datalen);
167 				printf(" %u", EXTRACT_32BITS(cp + 4));
168 				break;
169 			case TCP_OPT_CC:
170 				printf("cc");
171 				datalen = 4;
172 				LENCHECK(datalen);
173 				printf(" %u", EXTRACT_32BITS(cp));
174 				break;
175 			case TCP_OPT_CCNEW:
176 				printf("ccnew");
177 				datalen = 4;
178 				LENCHECK(datalen);
179 				printf(" %u", EXTRACT_32BITS(cp));
180 				break;
181 			case TCP_OPT_CCECHO:
182 				printf("ccecho");
183 				datalen = 4;
184 				LENCHECK(datalen);
185 				printf(" %u", EXTRACT_32BITS(cp));
186 				break;
187 			default:
188 				printf("opt-%d:", opt);
189 				datalen = len - 2;
190 				for (i = 0; i < datalen; ++i) {
191 					LENCHECK(i);
192 					printf("%02x", cp[i]);
193 				}
194 				break;
195 			}
196 			/* Account for data printed */
197 			cp += datalen;
198 			tcp_hl -= datalen;
199 
200 			/* Check specification against observed length */
201 			++datalen;                /* option octet */
202 			if (!TCP_OPT_TYPEONLY(opt))
203 				++datalen;              /* size octet */
204 			if (datalen != len)
205 				printf("[len %d]", len);
206 			ch = ',';
207 			if (opt == TCP_OPT_EOL)
208 				break;
209 		}
210 		putchar('>');
211 	}
212 	return;
213  bad:
214 	fputs("[bad opt]", stdout);
215 	if (ch != '\0')
216 		putchar('>');
217 	return;
218 }
219 
220 static void
_print_udp(u_char * p,int length)221 _print_udp(u_char *p, int length)
222 {
223 	struct ip_hdr *ip;
224 	struct udp_hdr *udp;
225 
226 	ip = (struct ip_hdr *)p;
227 	udp = (struct udp_hdr *)(p + (ip->ip_hl * 4));
228 
229 	/* XXX - truncation? */
230 	printf("%s.%d > %s.%d:", ip_ntoa(&ip->ip_src), ntohs(udp->uh_sport),
231 	    ip_ntoa(&ip->ip_dst), ntohs(udp->uh_dport));
232 
233 	printf(" udp %d", ntohs(udp->uh_ulen) - UDP_HDR_LEN);
234 }
235 
236 static void
_print_ip(u_char * p,int length)237 _print_ip(u_char *p, int length)
238 {
239 	struct ip_hdr *ip;
240 	u_int ip_off, ip_hl, ip_len;
241 
242 	ip = (struct ip_hdr *)p;
243 
244 	if (length < IP_HDR_LEN) {
245 		printf("truncated-ip %d", length);
246 		return;
247 	}
248 	ip_hl = ip->ip_hl * 4;
249 	ip_len = ntohs(ip->ip_len);
250 
251 	if (length < ip_len) {
252 		printf("truncated-ip - %d bytes missing!", ip_len - length);
253 		return;
254 	}
255 	ip_off = ntohs(ip->ip_off);
256 
257 	/* Handle first fragment. */
258 	if ((ip_off & IP_OFFMASK) == 0) {
259 		switch (ip->ip_p) {
260 		case IP_PROTO_TCP:
261 			_print_tcp(p, ip_len);
262 			break;
263 		case IP_PROTO_UDP:
264 			_print_udp(p, ip_len);
265 			break;
266 		case IP_PROTO_ICMP:
267 			_print_icmp(p, ip_len);
268 			break;
269 		default:
270 			printf("%s > %s:", ip_ntoa(&ip->ip_src),
271 			    ip_ntoa(&ip->ip_dst));
272 			printf(" ip-proto-%d %d", ip->ip_p, ip_len);
273 			break;
274 		}
275 	}
276 	/* Handle more frags. */
277 	if (ip_off & (IP_MF|IP_OFFMASK)) {
278 		if (ip_off & IP_OFFMASK)
279 			printf("%s > %s:", ip_ntoa(&ip->ip_src),
280 			    ip_ntoa(&ip->ip_dst));
281 		printf(" (frag %d:%d@%d%s)", ntohs(ip->ip_id), ip_len - ip_hl,
282 		    (ip_off & IP_OFFMASK) << 3, (ip_off & IP_MF) ? "+" : "");
283 	} else if (ip_off & IP_DF)
284 		printf(" (DF)");
285 
286 	if (ip->ip_tos)
287 		printf(" [tos 0x%x]", ip->ip_tos);
288 	if (ip->ip_ttl <= 1)
289 		printf(" [ttl %d]", ip->ip_ttl);
290 }
291 
292 static char *
timerntoa(struct timeval * tv)293 timerntoa(struct timeval *tv)
294 {
295 	static char buf[128];
296 	uint64_t usec;
297 
298 	usec = (tv->tv_sec * 1000000) + tv->tv_usec;
299 
300 	snprintf(buf, sizeof(buf), "%d.%03d ms",
301 	    (int)(usec / 1000), (int)(usec % 1000));
302 
303 	return (buf);
304 }
305 
306 int
print_apply(void * d,struct pktq * pktq)307 print_apply(void *d, struct pktq *pktq)
308 {
309 	struct pkt *pkt;
310 
311 	TAILQ_FOREACH(pkt, pktq, pkt_next) {
312 		_print_ip(pkt->pkt_eth_data, pkt->pkt_end - pkt->pkt_eth_data);
313 		if (timerisset(&pkt->pkt_ts))
314 			printf(" [delay %s]", timerntoa(&pkt->pkt_ts));
315 		printf("\n");
316 	}
317 	return (0);
318 }
319 
320 struct mod mod_print = {
321 	"print",		/* name */
322 	"print",		/* usage */
323 	NULL,			/* init */
324 	print_apply,		/* apply */
325 	NULL			/* close */
326 };
327