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