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