]> The Tcpdump Group git mirrors - tcpdump/blob - print-bootp.c
a44ef804b412473328516251c19ed29e4b1a3095
[tcpdump] / print-bootp.c
1 /*
2 * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that: (1) source code distributions
7 * retain the above copyright notice and this paragraph in its entirety, (2)
8 * distributions including binary code include the above copyright notice and
9 * this paragraph in its entirety in the documentation or other materials
10 * provided with the distribution, and (3) all advertising materials mentioning
11 * features or use of this software display the following acknowledgement:
12 * ``This product includes software developed by the University of California,
13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14 * the University nor the names of its contributors may be used to endorse
15 * or promote products derived from this software without specific prior
16 * written permission.
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 *
21 * Format and print bootp packets.
22 */
23 #ifndef lint
24 static const char rcsid[] =
25 "@(#) $Header: /tcpdump/master/tcpdump/print-bootp.c,v 1.65 2002-08-06 04:42:05 guy Exp $ (LBL)";
26 #endif
27
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31
32 #include <tcpdump-stdinc.h>
33
34 #include <stdio.h>
35 #include <string.h>
36
37 #include "interface.h"
38 #include "addrtoname.h"
39 #include "extract.h"
40 #include "ether.h"
41 #include "bootp.h"
42
43 static void rfc1048_print(const u_char *);
44 static void cmu_print(const u_char *);
45
46 static char tstr[] = " [|bootp]";
47
48 /*
49 * Print bootp requests
50 */
51 void
52 bootp_print(register const u_char *cp, u_int length,
53 u_short sport, u_short dport)
54 {
55 register const struct bootp *bp;
56 static const u_char vm_cmu[4] = VM_CMU;
57 static const u_char vm_rfc1048[4] = VM_RFC1048;
58
59 bp = (const struct bootp *)cp;
60 TCHECK(bp->bp_op);
61 switch (bp->bp_op) {
62
63 case BOOTREQUEST:
64 /* Usually, a request goes from a client to a server */
65 if (sport != IPPORT_BOOTPC || dport != IPPORT_BOOTPS)
66 printf(" (request)");
67 break;
68
69 case BOOTREPLY:
70 /* Usually, a reply goes from a server to a client */
71 if (sport != IPPORT_BOOTPS || dport != IPPORT_BOOTPC)
72 printf(" (reply)");
73 break;
74
75 default:
76 printf(" bootp-#%d", bp->bp_op);
77 }
78
79 TCHECK(bp->bp_secs);
80
81 /* The usual hardware address type is 1 (10Mb Ethernet) */
82 if (bp->bp_htype != 1)
83 printf(" htype-#%d", bp->bp_htype);
84
85 /* The usual length for 10Mb Ethernet address is 6 bytes */
86 if (bp->bp_htype != 1 || bp->bp_hlen != 6)
87 printf(" hlen:%d", bp->bp_hlen);
88
89 /* Only print interesting fields */
90 if (bp->bp_hops)
91 printf(" hops:%d", bp->bp_hops);
92 if (bp->bp_xid)
93 printf(" xid:0x%x", (u_int32_t)ntohl(bp->bp_xid));
94 if (bp->bp_secs)
95 printf(" secs:%d", ntohs(bp->bp_secs));
96 if (bp->bp_flags)
97 printf(" flags:0x%x", ntohs(bp->bp_flags));
98
99 /* Client's ip address */
100 TCHECK(bp->bp_ciaddr);
101 if (bp->bp_ciaddr.s_addr)
102 printf(" C:%s", ipaddr_string(&bp->bp_ciaddr));
103
104 /* 'your' ip address (bootp client) */
105 TCHECK(bp->bp_yiaddr);
106 if (bp->bp_yiaddr.s_addr)
107 printf(" Y:%s", ipaddr_string(&bp->bp_yiaddr));
108
109 /* Server's ip address */
110 TCHECK(bp->bp_siaddr);
111 if (bp->bp_siaddr.s_addr)
112 printf(" S:%s", ipaddr_string(&bp->bp_siaddr));
113
114 /* Gateway's ip address */
115 TCHECK(bp->bp_giaddr);
116 if (bp->bp_giaddr.s_addr)
117 printf(" G:%s", ipaddr_string(&bp->bp_giaddr));
118
119 /* Client's Ethernet address */
120 if (bp->bp_htype == 1 && bp->bp_hlen == 6) {
121 register const struct ether_header *eh;
122 register const char *e;
123
124 TCHECK2(bp->bp_chaddr[0], 6);
125 eh = (const struct ether_header *)packetp;
126 if (bp->bp_op == BOOTREQUEST)
127 e = (const char *)ESRC(eh);
128 else if (bp->bp_op == BOOTREPLY)
129 e = (const char *)EDST(eh);
130 else
131 e = 0;
132 if (e == 0 || memcmp((const char *)bp->bp_chaddr, e, 6) != 0)
133 printf(" ether %s", etheraddr_string(bp->bp_chaddr));
134 }
135
136 TCHECK2(bp->bp_sname[0], 1); /* check first char only */
137 if (*bp->bp_sname) {
138 printf(" sname \"");
139 if (fn_print(bp->bp_sname, snapend)) {
140 putchar('"');
141 fputs(tstr + 1, stdout);
142 return;
143 }
144 putchar('"');
145 }
146 TCHECK2(bp->bp_sname[0], 1); /* check first char only */
147 if (*bp->bp_file) {
148 printf(" file \"");
149 if (fn_print(bp->bp_file, snapend)) {
150 putchar('"');
151 fputs(tstr + 1, stdout);
152 return;
153 }
154 putchar('"');
155 }
156
157 /* Decode the vendor buffer */
158 TCHECK(bp->bp_vend[0]);
159 if (memcmp((const char *)bp->bp_vend, vm_rfc1048,
160 sizeof(u_int32_t)) == 0)
161 rfc1048_print(bp->bp_vend);
162 else if (memcmp((const char *)bp->bp_vend, vm_cmu,
163 sizeof(u_int32_t)) == 0)
164 cmu_print(bp->bp_vend);
165 else {
166 u_int32_t ul;
167
168 ul = EXTRACT_32BITS(&bp->bp_vend);
169 if (ul != 0)
170 printf("vend-#0x%x", ul);
171 }
172
173 return;
174 trunc:
175 fputs(tstr, stdout);
176 }
177
178 /*
179 * The first character specifies the format to print:
180 * i - ip address (32 bits)
181 * p - ip address pairs (32 bits + 32 bits)
182 * l - long (32 bits)
183 * L - unsigned long (32 bits)
184 * s - short (16 bits)
185 * b - period-seperated decimal bytes (variable length)
186 * x - colon-seperated hex bytes (variable length)
187 * a - ascii string (variable length)
188 * B - on/off (8 bits)
189 * $ - special (explicit code to handle)
190 */
191 static struct tok tag2str[] = {
192 /* RFC1048 tags */
193 { TAG_PAD, " PAD" },
194 { TAG_SUBNET_MASK, "iSM" }, /* subnet mask (RFC950) */
195 { TAG_TIME_OFFSET, "LTZ" }, /* seconds from UTC */
196 { TAG_GATEWAY, "iDG" }, /* default gateway */
197 { TAG_TIME_SERVER, "iTS" }, /* time servers (RFC868) */
198 { TAG_NAME_SERVER, "iIEN" }, /* IEN name servers (IEN116) */
199 { TAG_DOMAIN_SERVER, "iNS" }, /* domain name (RFC1035) */
200 { TAG_LOG_SERVER, "iLOG" }, /* MIT log servers */
201 { TAG_COOKIE_SERVER, "iCS" }, /* cookie servers (RFC865) */
202 { TAG_LPR_SERVER, "iLPR" }, /* lpr server (RFC1179) */
203 { TAG_IMPRESS_SERVER, "iIM" }, /* impress servers (Imagen) */
204 { TAG_RLP_SERVER, "iRL" }, /* resource location (RFC887) */
205 { TAG_HOSTNAME, "aHN" }, /* ascii hostname */
206 { TAG_BOOTSIZE, "sBS" }, /* 512 byte blocks */
207 { TAG_END, " END" },
208 /* RFC1497 tags */
209 { TAG_DUMPPATH, "aDP" },
210 { TAG_DOMAINNAME, "aDN" },
211 { TAG_SWAP_SERVER, "iSS" },
212 { TAG_ROOTPATH, "aRP" },
213 { TAG_EXTPATH, "aEP" },
214 /* RFC2132 tags */
215 { TAG_IP_FORWARD, "BIPF" },
216 { TAG_NL_SRCRT, "BSRT" },
217 { TAG_PFILTERS, "pPF" },
218 { TAG_REASS_SIZE, "sRSZ" },
219 { TAG_DEF_TTL, "bTTL" },
220 { TAG_MTU_TIMEOUT, "lMA" },
221 { TAG_MTU_TABLE, "sMT" },
222 { TAG_INT_MTU, "sMTU" },
223 { TAG_LOCAL_SUBNETS, "BLSN" },
224 { TAG_BROAD_ADDR, "iBR" },
225 { TAG_DO_MASK_DISC, "BMD" },
226 { TAG_SUPPLY_MASK, "BMS" },
227 { TAG_DO_RDISC, "BRD" },
228 { TAG_RTR_SOL_ADDR, "iRSA" },
229 { TAG_STATIC_ROUTE, "pSR" },
230 { TAG_USE_TRAILERS, "BUT" },
231 { TAG_ARP_TIMEOUT, "lAT" },
232 { TAG_ETH_ENCAP, "BIE" },
233 { TAG_TCP_TTL, "bTT" },
234 { TAG_TCP_KEEPALIVE, "lKI" },
235 { TAG_KEEPALIVE_GO, "BKG" },
236 { TAG_NIS_DOMAIN, "aYD" },
237 { TAG_NIS_SERVERS, "iYS" },
238 { TAG_NTP_SERVERS, "iNTP" },
239 { TAG_VENDOR_OPTS, "bVO" },
240 { TAG_NETBIOS_NS, "iWNS" },
241 { TAG_NETBIOS_DDS, "iWDD" },
242 { TAG_NETBIOS_NODE, "$WNT" },
243 { TAG_NETBIOS_SCOPE, "aWSC" },
244 { TAG_XWIN_FS, "iXFS" },
245 { TAG_XWIN_DM, "iXDM" },
246 { TAG_NIS_P_DOMAIN, "sN+D" },
247 { TAG_NIS_P_SERVERS, "iN+S" },
248 { TAG_MOBILE_HOME, "iMH" },
249 { TAG_SMPT_SERVER, "iSMTP" },
250 { TAG_POP3_SERVER, "iPOP3" },
251 { TAG_NNTP_SERVER, "iNNTP" },
252 { TAG_WWW_SERVER, "iWWW" },
253 { TAG_FINGER_SERVER, "iFG" },
254 { TAG_IRC_SERVER, "iIRC" },
255 { TAG_STREETTALK_SRVR, "iSTS" },
256 { TAG_STREETTALK_STDA, "iSTDA" },
257 { TAG_REQUESTED_IP, "iRQ" },
258 { TAG_IP_LEASE, "lLT" },
259 { TAG_OPT_OVERLOAD, "$OO" },
260 { TAG_TFTP_SERVER, "aTFTP" },
261 { TAG_BOOTFILENAME, "aBF" },
262 { TAG_DHCP_MESSAGE, " DHCP" },
263 { TAG_SERVER_ID, "iSID" },
264 { TAG_PARM_REQUEST, "bPR" },
265 { TAG_MESSAGE, "aMSG" },
266 { TAG_MAX_MSG_SIZE, "sMSZ" },
267 { TAG_RENEWAL_TIME, "lRN" },
268 { TAG_REBIND_TIME, "lRB" },
269 { TAG_VENDOR_CLASS, "aVC" },
270 { TAG_CLIENT_ID, "$CID" },
271 /* RFC 2485 */
272 { TAG_OPEN_GROUP_UAP, "aUAP" },
273 /* RFC 2563 */
274 { TAG_DISABLE_AUTOCONF, "BNOAUTO" },
275 /* RFC 2610 */
276 { TAG_SLP_DA, "bSLP-DA" }, /*"b" is a little wrong */
277 { TAG_SLP_SCOPE, "bSLP-SCOPE" }, /*"b" is a little wrong */
278 /* RFC 2937 */
279 { TAG_NS_SEARCH, "sNSSEARCH" }, /* XXX 's' */
280 /* RFC 3011 */
281 { TAG_IP4_SUBNET_SELECT, "iSUBNET" },
282 /* ftp://ftp.isi.edu/.../assignments/bootp-dhcp-extensions */
283 { TAG_USER_CLASS, "aCLASS" },
284 { TAG_SLP_NAMING_AUTH, "aSLP-NA" },
285 { TAG_CLIENT_FQDN, "$FQDN" },
286 { TAG_AGENT_CIRCUIT, "bACKT" },
287 { TAG_AGENT_REMOTE, "bARMT" },
288 { TAG_AGENT_MASK, "bAMSK" },
289 { TAG_TZ_STRING, "aTZSTR" },
290 { TAG_FQDN_OPTION, "bFQDNS" }, /* XXX 'b' */
291 { TAG_AUTH, "bAUTH" }, /* XXX 'b' */
292 { TAG_VINES_SERVERS, "iVINES" },
293 { TAG_SERVER_RANK, "sRANK" },
294 { TAG_CLIENT_ARCH, "sARCH" },
295 { TAG_CLIENT_NDI, "bNDI" }, /* XXX 'b' */
296 { TAG_CLIENT_GUID, "bGUID" }, /* XXX 'b' */
297 { TAG_LDAP_URL, "aLDAP" },
298 { TAG_6OVER4, "i6o4" },
299 { TAG_PRINTER_NAME, "aPRTR" },
300 { TAG_MDHCP_SERVER, "bMDHCP" }, /* XXX 'b' */
301 { TAG_IPX_COMPAT, "bIPX" }, /* XXX 'b' */
302 { TAG_NETINFO_PARENT, "iNI" },
303 { TAG_NETINFO_PARENT_TAG, "aNITAG" },
304 { TAG_URL, "aURL" },
305 { TAG_FAILOVER, "bFAIL" }, /* XXX 'b' */
306 { 0, NULL }
307 };
308 /* 2-byte extended tags */
309 static struct tok xtag2str[] = {
310 { 0, NULL }
311 };
312
313 /* DHCP "options overload" types */
314 static struct tok oo2str[] = {
315 { 1, "file" },
316 { 2, "sname" },
317 { 3, "file+sname" },
318 { 0, NULL }
319 };
320
321 /* NETBIOS over TCP/IP node type options */
322 static struct tok nbo2str[] = {
323 { 0x1, "b-node" },
324 { 0x2, "p-node" },
325 { 0x4, "m-node" },
326 { 0x8, "h-node" },
327 { 0, NULL }
328 };
329
330 /* ARP Hardware types, for Client-ID option */
331 static struct tok arp2str[] = {
332 { 0x1, "ether" },
333 { 0x6, "ieee802" },
334 { 0x7, "arcnet" },
335 { 0xf, "frelay" },
336 { 0x17, "strip" },
337 { 0x18, "ieee1394" },
338 { 0, NULL }
339 };
340
341 static void
342 rfc1048_print(register const u_char *bp)
343 {
344 register u_int16_t tag;
345 register u_int len, size;
346 register const char *cp;
347 register char c;
348 int first;
349 u_int32_t ul;
350 u_int16_t us;
351 u_int8_t uc;
352
353 printf(" vend-rfc1048");
354
355 /* Step over magic cookie */
356 bp += sizeof(int32_t);
357
358 /* Loop while we there is a tag left in the buffer */
359 while (bp + 1 < snapend) {
360 tag = *bp++;
361 if (tag == TAG_PAD)
362 continue;
363 if (tag == TAG_END)
364 return;
365 if (tag == TAG_EXTENDED_OPTION) {
366 TCHECK2(*(bp + 1), 2);
367 tag = EXTRACT_16BITS(bp + 1);
368 /* XXX we don't know yet if the IANA will
369 * preclude overlap of 1-byte and 2-byte spaces.
370 * If not, we need to offset tag after this step.
371 */
372 cp = tok2str(xtag2str, "?xT%u", tag);
373 } else
374 cp = tok2str(tag2str, "?T%u", tag);
375 c = *cp++;
376 printf(" %s:", cp);
377
378 /* Get the length; check for truncation */
379 if (bp + 1 >= snapend) {
380 fputs(tstr, stdout);
381 return;
382 }
383 len = *bp++;
384 if (bp + len >= snapend) {
385 fputs(tstr, stdout);
386 return;
387 }
388
389 if (tag == TAG_DHCP_MESSAGE && len == 1) {
390 uc = *bp++;
391 switch (uc) {
392 case DHCPDISCOVER: printf("DISCOVER"); break;
393 case DHCPOFFER: printf("OFFER"); break;
394 case DHCPREQUEST: printf("REQUEST"); break;
395 case DHCPDECLINE: printf("DECLINE"); break;
396 case DHCPACK: printf("ACK"); break;
397 case DHCPNAK: printf("NACK"); break;
398 case DHCPRELEASE: printf("RELEASE"); break;
399 case DHCPINFORM: printf("INFORM"); break;
400 default: printf("%u", uc); break;
401 }
402 continue;
403 }
404
405 if (tag == TAG_PARM_REQUEST) {
406 first = 1;
407 while (len-- > 0) {
408 uc = *bp++;
409 cp = tok2str(tag2str, "?T%u", uc);
410 if (!first)
411 putchar('+');
412 printf("%s", cp + 1);
413 first = 0;
414 }
415 continue;
416 }
417 if (tag == TAG_EXTENDED_REQUEST) {
418 first = 1;
419 while (len > 1) {
420 len -= 2;
421 us = EXTRACT_16BITS(bp);
422 bp += 2;
423 cp = tok2str(xtag2str, "?xT%u", us);
424 if (!first)
425 putchar('+');
426 printf("%s", cp + 1);
427 first = 0;
428 }
429 continue;
430 }
431
432 /* Print data */
433 size = len;
434 if (c == '?') {
435 /* Base default formats for unknown tags on data size */
436 if (size & 1)
437 c = 'b';
438 else if (size & 2)
439 c = 's';
440 else
441 c = 'l';
442 }
443 first = 1;
444 switch (c) {
445
446 case 'a':
447 /* ascii strings */
448 putchar('"');
449 (void)fn_printn(bp, size, NULL);
450 putchar('"');
451 bp += size;
452 size = 0;
453 break;
454
455 case 'i':
456 case 'l':
457 case 'L':
458 /* ip addresses/32-bit words */
459 while (size >= sizeof(ul)) {
460 if (!first)
461 putchar(',');
462 ul = EXTRACT_32BITS(bp);
463 if (c == 'i') {
464 ul = htonl(ul);
465 printf("%s", ipaddr_string(&ul));
466 } else if (c == 'L')
467 printf("%d", ul);
468 else
469 printf("%u", ul);
470 bp += sizeof(ul);
471 size -= sizeof(ul);
472 first = 0;
473 }
474 break;
475
476 case 'p':
477 /* IP address pairs */
478 while (size >= 2*sizeof(ul)) {
479 if (!first)
480 putchar(',');
481 memcpy((char *)&ul, (const char *)bp, sizeof(ul));
482 printf("(%s:", ipaddr_string(&ul));
483 bp += sizeof(ul);
484 memcpy((char *)&ul, (const char *)bp, sizeof(ul));
485 printf("%s)", ipaddr_string(&ul));
486 bp += sizeof(ul);
487 size -= 2*sizeof(ul);
488 first = 0;
489 }
490 break;
491
492 case 's':
493 /* shorts */
494 while (size >= sizeof(us)) {
495 if (!first)
496 putchar(',');
497 us = EXTRACT_16BITS(bp);
498 printf("%u", us);
499 bp += sizeof(us);
500 size -= sizeof(us);
501 first = 0;
502 }
503 break;
504
505 case 'B':
506 /* boolean */
507 while (size > 0) {
508 if (!first)
509 putchar(',');
510 switch (*bp) {
511 case 0:
512 putchar('N');
513 break;
514 case 1:
515 putchar('Y');
516 break;
517 default:
518 printf("%u?", *bp);
519 break;
520 }
521 ++bp;
522 --size;
523 first = 0;
524 }
525 break;
526
527 case 'b':
528 case 'x':
529 default:
530 /* Bytes */
531 while (size > 0) {
532 if (!first)
533 putchar(c == 'x' ? ':' : '.');
534 if (c == 'x')
535 printf("%02x", *bp);
536 else
537 printf("%u", *bp);
538 ++bp;
539 --size;
540 first = 0;
541 }
542 break;
543
544 case '$':
545 /* Guys we can't handle with one of the usual cases */
546 switch (tag) {
547
548 case TAG_NETBIOS_NODE:
549 tag = *bp++;
550 --size;
551 fputs(tok2str(nbo2str, NULL, tag), stdout);
552 break;
553
554 case TAG_OPT_OVERLOAD:
555 tag = *bp++;
556 --size;
557 fputs(tok2str(oo2str, NULL, tag), stdout);
558 break;
559
560 case TAG_CLIENT_FQDN:
561 if (*bp++)
562 printf("[svrreg]");
563 if (*bp)
564 printf("%u/%u/", *bp, *(bp+1));
565 bp += 2;
566 putchar('"');
567 (void)fn_printn(bp, size - 3, NULL);
568 putchar('"');
569 bp += size - 3;
570 size = 0;
571 break;
572
573 case TAG_CLIENT_ID:
574 { int type = *bp++;
575 size--;
576 if (type == 0) {
577 putchar('"');
578 (void)fn_printn(bp, size, NULL);
579 putchar('"');
580 break;
581 } else {
582 printf("[%s]", tok2str(arp2str, "type-%d", type));
583 }
584 while (size > 0) {
585 if (!first)
586 putchar(':');
587 printf("%02x", *bp);
588 ++bp;
589 --size;
590 first = 0;
591 }
592 break;
593 }
594
595 default:
596 printf("[unknown special tag %u, size %u]",
597 tag, size);
598 bp += size;
599 size = 0;
600 break;
601 }
602 break;
603 }
604 /* Data left over? */
605 if (size)
606 printf("[len %u]", len);
607 }
608 return;
609 trunc:
610 printf("|[rfc1048]");
611 }
612
613 static void
614 cmu_print(register const u_char *bp)
615 {
616 register const struct cmu_vend *cmu;
617
618 #define PRINTCMUADDR(m, s) { TCHECK(cmu->m); \
619 if (cmu->m.s_addr != 0) \
620 printf(" %s:%s", s, ipaddr_string(&cmu->m.s_addr)); }
621
622 printf(" vend-cmu");
623 cmu = (const struct cmu_vend *)bp;
624
625 /* Only print if there are unknown bits */
626 TCHECK(cmu->v_flags);
627 if ((cmu->v_flags & ~(VF_SMASK)) != 0)
628 printf(" F:0x%x", cmu->v_flags);
629 PRINTCMUADDR(v_dgate, "DG");
630 PRINTCMUADDR(v_smask, cmu->v_flags & VF_SMASK ? "SM" : "SM*");
631 PRINTCMUADDR(v_dns1, "NS1");
632 PRINTCMUADDR(v_dns2, "NS2");
633 PRINTCMUADDR(v_ins1, "IEN1");
634 PRINTCMUADDR(v_ins2, "IEN2");
635 PRINTCMUADDR(v_ts1, "TS1");
636 PRINTCMUADDR(v_ts2, "TS2");
637 return;
638
639 trunc:
640 fputs(tstr, stdout);
641 #undef PRINTCMUADDR
642 }