print-bootp.c revision 1.2
1/*	$OpenBSD: print-bootp.c,v 1.2 1996/03/04 15:59:18 mickey Exp $	*/
2/*	$NetBSD: print-bootp.c,v 1.2 1995/03/06 19:11:05 mycroft Exp $	*/
3
4/*
5 * Copyright (c) 1990, 1991, 1993, 1994
6 *	The Regents of the University of California.  All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that: (1) source code distributions
10 * retain the above copyright notice and this paragraph in its entirety, (2)
11 * distributions including binary code include the above copyright notice and
12 * this paragraph in its entirety in the documentation or other materials
13 * provided with the distribution, and (3) all advertising materials mentioning
14 * features or use of this software display the following acknowledgement:
15 * ``This product includes software developed by the University of California,
16 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
17 * the University nor the names of its contributors may be used to endorse
18 * or promote products derived from this software without specific prior
19 * written permission.
20 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
21 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
22 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
23 *
24 * Format and print bootp packets.
25 */
26#ifndef lint
27static char rcsid[] =
28    "@(#) Header: print-bootp.c,v 1.30 94/06/14 20:17:37 leres Exp (LBL)";
29#endif
30
31#include <sys/param.h>
32#include <sys/time.h>
33#include <sys/types.h>
34#include <sys/socket.h>
35
36#include <net/if.h>
37
38#include <netinet/in.h>
39#include <netinet/if_ether.h>
40
41#include <ctype.h>
42#include <stdio.h>
43
44#include "interface.h"
45#include "addrtoname.h"
46#include "bootp.h"
47
48static void rfc1048_print(const u_char *, int);
49static void cmu_print(const u_char *, int);
50
51static char tstr[] = " [|bootp]";
52
53/*
54 * Print bootp requests
55 */
56void
57bootp_print(register const u_char *cp, int length,
58	    u_short sport, u_short dport)
59{
60	register const struct bootp *bp;
61	static u_char vm_cmu[4] = VM_CMU;
62	static u_char vm_rfc1048[4] = VM_RFC1048;
63	const u_char *ep;
64
65#define TCHECK(var, l) if ((u_char *)&(var) > ep - l) goto trunc
66
67	bp = (struct bootp *)cp;
68	/* 'ep' points to the end of avaible data. */
69	ep = snapend;
70
71	TCHECK(bp->bp_op, sizeof(bp->bp_op));
72	switch (bp->bp_op) {
73
74	case BOOTREQUEST:
75		/* Usually, a request goes from a client to a server */
76		if (sport != IPPORT_BOOTPC || dport != IPPORT_BOOTPS)
77			printf(" (request)");
78		break;
79
80	case BOOTREPLY:
81		/* Usually, a reply goes from a server to a client */
82		if (sport != IPPORT_BOOTPS || dport != IPPORT_BOOTPC)
83			printf(" (reply)");
84		break;
85
86	default:
87		printf(" bootp-#%d", bp->bp_op);
88	}
89
90	TCHECK(bp->bp_secs, sizeof(bp->bp_secs));
91
92	/* The usual hardware address type is 1 (10Mb Ethernet) */
93	if (bp->bp_htype != 1)
94		printf(" htype-#%d", bp->bp_htype);
95
96	/* The usual length for 10Mb Ethernet address is 6 bytes */
97	if (bp->bp_htype != 1 || bp->bp_hlen != 6)
98		printf(" hlen:%d", bp->bp_hlen);
99
100	/* Only print interesting fields */
101	if (bp->bp_hops)
102		printf(" hops:%d", bp->bp_hops);
103	if (bp->bp_xid)
104		printf(" xid:0x%x", ntohl(bp->bp_xid));
105	if (bp->bp_secs)
106		printf(" secs:%d", ntohs(bp->bp_secs));
107
108	/* Client's ip address */
109	TCHECK(bp->bp_ciaddr, sizeof(bp->bp_ciaddr));
110	if (bp->bp_ciaddr.s_addr)
111		printf(" C:%s", ipaddr_string(&bp->bp_ciaddr));
112
113	/* 'your' ip address (bootp client) */
114	TCHECK(bp->bp_yiaddr, sizeof(bp->bp_yiaddr));
115	if (bp->bp_yiaddr.s_addr)
116		printf(" Y:%s", ipaddr_string(&bp->bp_yiaddr));
117
118	/* Server's ip address */
119	TCHECK(bp->bp_siaddr, sizeof(bp->bp_siaddr));
120	if (bp->bp_siaddr.s_addr)
121		printf(" S:%s", ipaddr_string(&bp->bp_siaddr));
122
123	/* Gateway's ip address */
124	TCHECK(bp->bp_giaddr, sizeof(bp->bp_giaddr));
125	if (bp->bp_giaddr.s_addr)
126		printf(" G:%s", ipaddr_string(&bp->bp_giaddr));
127
128	/* Client's Ethernet address */
129	if (bp->bp_htype == 1 && bp->bp_hlen == 6) {
130		register const struct ether_header *eh;
131		register const char *e;
132
133		TCHECK(bp->bp_chaddr[0], 6);
134		eh = (struct ether_header *)packetp;
135		if (bp->bp_op == BOOTREQUEST)
136			e = (const char *)ESRC(eh);
137		else if (bp->bp_op == BOOTREPLY)
138			e = (const char *)EDST(eh);
139		else
140			e = 0;
141		if (e == 0 || bcmp((char *)bp->bp_chaddr, e, 6) != 0)
142			printf(" ether %s", etheraddr_string(bp->bp_chaddr));
143	}
144
145	TCHECK(bp->bp_sname[0], 1);		/* check first char only */
146	if (*bp->bp_sname) {
147		printf(" sname ");
148		if (fn_print(bp->bp_sname, ep)) {
149			fputs(tstr + 1, stdout);
150			return;
151		}
152	}
153	TCHECK(bp->bp_sname[0], 1);		/* check first char only */
154	if (*bp->bp_file) {
155		printf(" file ");
156		if (fn_print(bp->bp_file, ep)) {
157			fputs(tstr + 1, stdout);
158			return;
159		}
160	}
161
162	/* Decode the vendor buffer */
163	TCHECK(bp->bp_vend[0], sizeof(bp->bp_vend));
164	length -= sizeof(*bp) - sizeof(bp->bp_vend);
165	if (bcmp((char *)bp->bp_vend, (char *)vm_rfc1048,
166		 sizeof(u_int32)) == 0)
167		rfc1048_print(bp->bp_vend, length);
168	else if (bcmp((char *)bp->bp_vend, (char *)vm_cmu,
169		      sizeof(u_int32)) == 0)
170		cmu_print(bp->bp_vend, length);
171	else {
172		u_int32 ul;
173
174		bcopy((char *)bp->bp_vend, (char *)&ul, sizeof(ul));
175		if (ul != 0)
176			printf("vend-#0x%x", ul);
177	}
178
179	return;
180trunc:
181	fputs(tstr, stdout);
182#undef TCHECK
183}
184
185/* The first character specifies the format to print */
186static struct token tag2str[] = {
187/* RFC1048 tags */
188	{ TAG_PAD,		" PAD" },
189	{ TAG_SUBNET_MASK,	"iSM" },	/* subnet mask (RFC950) */
190	{ TAG_TIME_OFFSET,	"lTZ" },	/* seconds from UTC */
191	{ TAG_GATEWAY,		"iDG" },	/* default gateway */
192	{ TAG_TIME_SERVER,	"iTS" },	/* time servers (RFC868) */
193	{ TAG_NAME_SERVER,	"iIEN" },	/* IEN name servers (IEN116) */
194	{ TAG_DOMAIN_SERVER,	"iNS" },	/* domain name (RFC1035) */
195	{ TAG_LOG_SERVER,	"iLOG" },	/* MIT log servers */
196	{ TAG_COOKIE_SERVER,	"iCS" },	/* cookie servers (RFC865) */
197	{ TAG_LPR_SERVER,	"iLPR" },	/* lpr server (RFC1179) */
198	{ TAG_IMPRESS_SERVER,	"iIM" },	/* impress servers (Imagen) */
199	{ TAG_RLP_SERVER,	"iRL" },	/* resource location (RFC887) */
200	{ TAG_HOSTNAME,		"aHN" },	/* ascii hostname */
201	{ TAG_BOOTSIZE,		"sBS" },	/* 512 byte blocks */
202	{ TAG_END,		" END" },
203/* RFC1497 tags */
204	{ TAG_DUMPPATH,		"aDP" },
205	{ TAG_DOMAINNAME,	"aDN" },
206	{ TAG_SWAP_SERVER,	"iSS" },
207	{ TAG_ROOTPATH,		"aRP" },
208	{ TAG_EXTPATH,		"aEP" },
209	{ 0,			NULL }
210};
211
212static void
213rfc1048_print(register const u_char *bp, register int length)
214{
215	register u_char tag;
216	register const u_char *ep;
217	register u_int len, size;
218	register const char *cp;
219	register char c;
220	int first;
221	u_int32 ul;
222	u_short us;
223
224	printf(" vend-rfc1048");
225
226	/* Setup end pointer */
227	ep = bp + length;
228
229	/* Step over magic cookie */
230	bp += sizeof(int32);
231
232	/* Loop while we there is a tag left in the buffer */
233	while (bp + 1 < ep) {
234		tag = *bp++;
235		if (tag == TAG_PAD)
236			continue;
237		if (tag == TAG_END)
238			return;
239		cp = tok2str(tag2str, "?T%d", tag);
240		c = *cp++;
241		printf(" %s:", cp);
242
243		/* Get the length; check for truncation */
244		if (bp + 1 >= ep) {
245			fputs(tstr, stdout);
246			return;
247		}
248		len = *bp++;
249		if (bp + len >= ep) {
250			fputs(tstr, stdout);
251			return;
252		}
253
254		/* Print data */
255		size = len;
256		if (c == '?') {
257			/* Base default formats for unknown tags on data size */
258			if (size & 1)
259				c = 'b';
260			else if (size & 2)
261				c = 's';
262			else
263				c = 'l';
264		}
265		first = 1;
266		switch (c) {
267
268		case 'a':
269			/* ascii strings */
270			(void)fn_printn(bp, size, NULL);
271			bp += size;
272			size = 0;
273			break;
274
275		case 'i':
276		case 'l':
277			/* ip addresses/32-bit words */
278			while (size >= sizeof(ul)) {
279				if (!first)
280					putchar(',');
281				bcopy((char *)bp, (char *)&ul, sizeof(ul));
282				if (c == 'i')
283					printf("%s", ipaddr_string(&ul));
284				else
285					printf("%lu", ul);
286				bp += sizeof(ul);
287				size -= sizeof(ul);
288				first = 0;
289			}
290			break;
291
292		case 's':
293			/* shorts */
294			while (size >= sizeof(us)) {
295				if (!first)
296					putchar(',');
297				bcopy((char *)bp, (char *)&us, sizeof(us));
298				printf("%d", us);
299				bp += sizeof(us);
300				size -= sizeof(us);
301				first = 0;
302			}
303			break;
304
305		case 'b':
306		default:
307			/* Bytes */
308			while (size > 0) {
309				if (!first)
310					putchar('.');
311				printf("%d", *bp);
312				++bp;
313				--size;
314				first = 0;
315			}
316			break;
317		}
318		/* Data left over? */
319		if (size)
320			printf("[len %d]", len);
321	}
322}
323
324static void
325cmu_print(register const u_char *bp, register int length)
326{
327	register const struct cmu_vend *cmu;
328	register const u_char *ep;
329	char *fmt = " %s:%s";
330
331#define TCHECK(var, l) if ((u_char *)&(var) > ep - l) goto trunc
332#define PRINTCMUADDR(m, s) { TCHECK(cmu->m, sizeof(cmu->m)); \
333    if (cmu->m.s_addr != 0) \
334	printf(fmt, s, ipaddr_string(&cmu->m.s_addr)); }
335
336	/* Setup end pointer */
337	ep = bp + length;
338
339	printf(" vend-cmu");
340	cmu = (struct cmu_vend *)bp;
341
342	/* Only print if there are unknown bits */
343	TCHECK(cmu->v_flags, sizeof(cmu->v_flags));
344	if ((cmu->v_flags & ~(VF_SMASK)) != 0)
345		printf(" F:0x%x", cmu->v_flags);
346	PRINTCMUADDR(v_dgate, "DG");
347	PRINTCMUADDR(v_smask, cmu->v_flags & VF_SMASK ? "SM" : "SM*");
348	PRINTCMUADDR(v_dns1, "NS1");
349	PRINTCMUADDR(v_dns2, "NS2");
350	PRINTCMUADDR(v_ins1, "IEN1");
351	PRINTCMUADDR(v_ins2, "IEN2");
352	PRINTCMUADDR(v_ts1, "TS1");
353	PRINTCMUADDR(v_ts2, "TS2");
354	return;
355
356trunc:
357	fputs(tstr, stdout);
358#undef TCHECK
359#undef PRINTCMUADDR
360}
361