1 /*
2 print.c
3
4 Dug Song <dugsong@anzen.com>
5
6 Copyright (c) 1999 Anzen Computing. All rights reserved.
7
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions
10 are met:
11
12 1. Redistributions of source code must retain the above copyright
13 notice, this list of conditions and the following disclaimer.
14 2. Redistributions in binary form must reproduce the above copyright
15 notice, this list of conditions and the following disclaimer in the
16 documentation and/or other materials provided with the distribution.
17 3. All advertising materials mentioning features or use of this software
18 must display the following acknowledgement:
19 This product includes software developed by Anzen Computing.
20 4. Neither the name of Anzen Computing nor the names of its
21 contributors may be used to endorse or promote products derived
22 from this software without specific prior written permission.
23
24 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
25 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
28 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
30 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
32 IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
33 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
34 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35
36 $Id: print.c,v 1.2 1999/05/27 02:39:38 dugsong Exp $
37 */
38
39 #ifdef STDC_HEADERS
40 #include <stdio.h>
41 #endif
42 #include <libnet.h>
43 #include "print.h"
44
45 /* The following code is an adaptation of the print-* code in tcpdump. */
46
47 /* Compatibility */
48 #ifndef TCPOPT_WSCALE
49 #define TCPOPT_WSCALE 3 /* window scale factor (rfc1072) */
50 #endif
51 #ifndef TCPOPT_SACKOK
52 #define TCPOPT_SACKOK 4 /* selective ack ok (rfc2018) */
53 #endif
54 #ifndef TCPOPT_SACK
55 #define TCPOPT_SACK 5 /* selective ack (rfc2018) */
56 #endif
57 #ifndef TCPOLEN_SACK
58 #define TCPOLEN_SACK 8 /* length of a SACK block */
59 #endif
60 #ifndef TCPOPT_ECHO
61 #define TCPOPT_ECHO 6 /* echo (rfc1072) */
62 #endif
63 #ifndef TCPOPT_ECHOREPLY
64 #define TCPOPT_ECHOREPLY 7 /* echo (rfc1072) */
65 #endif
66 #ifndef TCPOPT_TIMESTAMP
67 #define TCPOPT_TIMESTAMP 8 /* timestamps (rfc1323) */
68 #endif
69 #ifndef TCPOPT_CC
70 #define TCPOPT_CC 11 /* T/TCP CC options (rfc1644) */
71 #endif
72 #ifndef TCPOPT_CCNEW
73 #define TCPOPT_CCNEW 12 /* T/TCP CC options (rfc1644) */
74 #endif
75 #ifndef TCPOPT_CCECHO
76 #define TCPOPT_CCECHO 13 /* T/TCP CC options (rfc1644) */
77 #endif
78
79 #ifndef IP_OFFMASK
80 #define IP_OFFMASK 0x1fff
81 #endif
82
83 #define EXTRACT_16BITS(p) \
84 ((u_short)ntohs(*(u_short *)(p)))
85 #define EXTRACT_32BITS(p) \
86 ((u_long)ntohl(*(u_long *)(p)))
87
88 void
print_ip(unsigned char * bp,int length)89 print_ip(unsigned char *bp, int length)
90 {
91 struct ip *iph;
92 u_int ip_off, ip_hl, ip_len;
93
94 iph = (struct ip *)bp;
95
96 if (length < IP_H) {
97 printf("truncated-ip %d", length);
98 return;
99 }
100 ip_hl = iph->ip_hl * 4;
101 ip_len = ntohs(iph->ip_len);
102
103 if (length < ip_len) {
104 printf("truncated-ip - %d bytes missing!", ip_len - length);
105 return;
106 }
107 ip_off = ntohs(iph->ip_off);
108
109 /* Handle first fragment. */
110 if ((ip_off & IP_OFFMASK) == 0) {
111 switch (iph->ip_p) {
112
113 case IPPROTO_TCP:
114 print_tcp(bp, ip_len);
115 break;
116
117 case IPPROTO_UDP:
118 print_udp(bp, ip_len);
119 break;
120
121 case IPPROTO_ICMP:
122 print_icmp(bp, ip_len);
123 break;
124
125 default:
126 printf("%s > %s:", libnet_host_lookup(iph->ip_src.s_addr, 0),
127 libnet_host_lookup(iph->ip_dst.s_addr, 0));
128 printf(" ip-proto-%d %d", iph->ip_p, ip_len);
129 break;
130 }
131 }
132 /* Handle more frags. */
133 if (ip_off & (IP_MF|IP_OFFMASK)) {
134 if (ip_off & IP_OFFMASK)
135 printf("%s > %s:", libnet_host_lookup(iph->ip_src.s_addr, 0),
136 libnet_host_lookup(iph->ip_dst.s_addr, 0));
137
138 printf(" (frag %d:%d@%d%s)", ntohs(iph->ip_id), ip_len - ip_hl,
139 (ip_off & IP_OFFMASK) << 3, (ip_off & IP_MF) ? "+" : "");
140 }
141 /* Handle don't frags. */
142 else if (ip_off & IP_DF) printf(" (DF)");
143
144 if (iph->ip_tos) printf(" [tos 0x%x]", (int)iph->ip_tos);
145 if (iph->ip_ttl <= 1) printf(" [ttl %d]", (int)iph->ip_ttl);
146 }
147
148 void
print_udp(unsigned char * bp,int length)149 print_udp(unsigned char *bp, int length)
150 {
151 struct ip *iph;
152 struct udphdr *udph;
153
154 iph = (struct ip *)bp;
155 udph = (struct udphdr *)(bp + (iph->ip_hl * 4));
156
157 printf("%s.%d > %s.%d:", libnet_host_lookup(iph->ip_src.s_addr, 0),
158 ntohs(udph->uh_sport), libnet_host_lookup(iph->ip_dst.s_addr, 0),
159 ntohs(udph->uh_dport));
160
161 printf(" udp %d", ntohs(udph->uh_ulen) - UDP_H);
162 }
163
164 void
print_icmp(unsigned char * bp,int length)165 print_icmp(unsigned char *bp, int length)
166 {
167 struct ip *iph;
168 struct libnet_icmp_hdr *icmph;
169
170 iph = (struct ip *)bp;
171 icmph = (struct libnet_icmp_hdr *)(bp + (iph->ip_hl * 4));
172
173 printf("%s > %s:", libnet_host_lookup(iph->ip_src.s_addr, 0),
174 libnet_host_lookup(iph->ip_dst.s_addr, 0));
175
176 printf(" icmp: type %d code %d", icmph->icmp_type, icmph->icmp_code);
177 }
178
179 void
print_tcp(unsigned char * bp,int length)180 print_tcp(unsigned char *bp, int length)
181 {
182 struct ip *iph;
183 struct tcphdr *tcph;
184 u_short sport, dport, win, urp;
185 u_long seq, ack;
186 int len, tcp_hl;
187 register char ch;
188
189 iph = (struct ip *)bp;
190 tcph = (struct tcphdr *)(bp + (iph->ip_hl * 4));
191 len = length - (iph->ip_hl * 4);
192
193 if (len < TCP_H) {
194 printf("truncated-tcp %d", len);
195 return;
196 }
197 sport = ntohs(tcph->th_sport);
198 dport = ntohs(tcph->th_dport);
199 seq = ntohl(tcph->th_seq);
200 ack = ntohl(tcph->th_ack);
201 win = ntohs(tcph->th_win);
202 urp = ntohs(tcph->th_urp);
203 tcp_hl = tcph->th_off * 4;
204
205 printf("%s.%d > %s.%d: ", libnet_host_lookup(iph->ip_src.s_addr, 0), sport,
206 libnet_host_lookup(iph->ip_dst.s_addr, 0), dport);
207
208 if (tcph->th_flags & (TH_SYN|TH_FIN|TH_RST|TH_PUSH)) {
209 if (tcph->th_flags & TH_SYN) putchar('S');
210 if (tcph->th_flags & TH_FIN) putchar('F');
211 if (tcph->th_flags & TH_RST) putchar('R');
212 if (tcph->th_flags & TH_PUSH) putchar('P');
213 }
214 else putchar('.');
215
216 if (tcp_hl > len) {
217 printf(" [bad hdr length]");
218 return;
219 }
220 len -= tcp_hl;
221
222 if (len > 0 || tcph->th_flags & (TH_SYN | TH_FIN | TH_RST))
223 printf(" %lu:%lu(%d)", seq, seq + len, len);
224
225 if (tcph->th_flags & TH_ACK) printf(" ack %lu", ack);
226 printf(" win %d", win);
227 if (tcph->th_flags & TH_URG) printf(" urg %d", urp);
228
229 /* Handle options. */
230 if ((tcp_hl -= TCP_H) > 0) {
231 register const u_char *cp;
232 register int i, opt, len, datalen;
233
234 cp = (const u_char *)tcph + TCP_H;
235 putchar(' ');
236 ch = '<';
237
238 #define ZEROLENOPT(o) ((o) == TCPOPT_EOL || (o) == TCPOPT_NOP)
239
240 while (tcp_hl > 0) {
241 putchar(ch);
242 opt = *cp++;
243 if (ZEROLENOPT(opt))
244 len = 1;
245 else {
246 len = *cp++; /* total including type, len */
247 if (len < 2 || len > tcp_hl)
248 goto bad;
249 --tcp_hl; /* account for length byte */
250 }
251 --tcp_hl; /* account for type byte */
252 datalen = 0;
253
254 /* Bail if "l" bytes of data are not left or were not captured */
255 #define LENCHECK(l) { if ((l) > tcp_hl) goto bad; }
256
257 switch (opt) {
258
259 case TCPOPT_MAXSEG:
260 printf("mss");
261 datalen = 2;
262 LENCHECK(datalen);
263 printf(" %u", EXTRACT_16BITS(cp));
264 break;
265
266 case TCPOPT_EOL:
267 printf("eol");
268 break;
269
270 case TCPOPT_NOP:
271 printf("nop");
272 break;
273
274 case TCPOPT_WSCALE:
275 printf("wscale");
276 datalen = 1;
277 LENCHECK(datalen);
278 printf(" %u", *cp);
279 break;
280
281 case TCPOPT_SACKOK:
282 printf("sackOK");
283 if (len != 2)
284 printf("[len %d]", len);
285 break;
286
287 case TCPOPT_SACK:
288 datalen = len - 2;
289 if ((datalen % TCPOLEN_SACK) != 0 || !(tcph->th_flags & TH_ACK)) {
290 printf("malformed sack ");
291 printf("[len %d] ", datalen);
292 break;
293 }
294 printf("sack %d ", datalen/TCPOLEN_SACK);
295 break;
296
297 case TCPOPT_ECHO:
298 printf("echo");
299 datalen = 4;
300 LENCHECK(datalen);
301 printf(" %lu", EXTRACT_32BITS(cp));
302 break;
303
304 case TCPOPT_ECHOREPLY:
305 printf("echoreply");
306 datalen = 4;
307 LENCHECK(datalen);
308 printf(" %lu", EXTRACT_32BITS(cp));
309 break;
310
311 case TCPOPT_TIMESTAMP:
312 printf("timestamp");
313 datalen = 8;
314 LENCHECK(4);
315 printf(" %lu", EXTRACT_32BITS(cp));
316 LENCHECK(datalen);
317 printf(" %lu", EXTRACT_32BITS(cp + 4));
318 break;
319
320 case TCPOPT_CC:
321 printf("cc");
322 datalen = 4;
323 LENCHECK(datalen);
324 printf(" %lu", EXTRACT_32BITS(cp));
325 break;
326
327 case TCPOPT_CCNEW:
328 printf("ccnew");
329 datalen = 4;
330 LENCHECK(datalen);
331 printf(" %lu", EXTRACT_32BITS(cp));
332 break;
333
334 case TCPOPT_CCECHO:
335 printf("ccecho");
336 datalen = 4;
337 LENCHECK(datalen);
338 printf(" %lu", EXTRACT_32BITS(cp));
339 break;
340
341 default:
342 printf("opt-%d:", opt);
343 datalen = len - 2;
344 for (i = 0; i < datalen; ++i) {
345 LENCHECK(i);
346 printf("%02x", cp[i]);
347 }
348 break;
349 }
350 /* Account for data printed */
351 cp += datalen;
352 tcp_hl -= datalen;
353
354 /* Check specification against observed length */
355 ++datalen; /* option octet */
356 if (!ZEROLENOPT(opt))
357 ++datalen; /* size octet */
358 if (datalen != len)
359 printf("[len %d]", len);
360 ch = ',';
361 if (opt == TCPOPT_EOL)
362 break;
363 }
364 putchar('>');
365 }
366 return;
367
368 bad:
369 fputs("[bad opt]", stdout);
370 if (ch != '\0')
371 putchar('>');
372 return;
373 }
374
375
376