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 * $FreeBSD$ 24 */ 25 #ifndef lint 26 static const char rcsid[] = 27 "@(#) $Header: /tcpdump/master/tcpdump/print-bootp.c,v 1.56 2000/12/04 00:00:08 fenner Exp $ (LBL)"; 28 #endif 29 30 #ifdef HAVE_CONFIG_H 31 #include "config.h" 32 #endif 33 34 #include <sys/param.h> 35 #include <sys/time.h> 36 #include <sys/socket.h> 37 38 struct mbuf; 39 struct rtentry; 40 41 #include <netinet/in.h> 42 43 #include <ctype.h> 44 #include <stdio.h> 45 #include <string.h> 46 47 #include "interface.h" 48 #include "addrtoname.h" 49 #include "extract.h" 50 #include "ether.h" 51 #include "bootp.h" 52 53 static void rfc1048_print(const u_char *, u_int); 54 static void cmu_print(const u_char *, u_int); 55 56 static char tstr[] = " [|bootp]"; 57 58 /* 59 * Print bootp requests 60 */ 61 void 62 bootp_print(register const u_char *cp, u_int length, 63 u_short sport, u_short dport) 64 { 65 register const struct bootp *bp; 66 static u_char vm_cmu[4] = VM_CMU; 67 static u_char vm_rfc1048[4] = VM_RFC1048; 68 69 bp = (struct bootp *)cp; 70 TCHECK(bp->bp_op); 71 switch (bp->bp_op) { 72 73 case BOOTREQUEST: 74 /* Usually, a request goes from a client to a server */ 75 if (sport != IPPORT_BOOTPC || dport != IPPORT_BOOTPS) 76 printf(" (request)"); 77 break; 78 79 case BOOTREPLY: 80 /* Usually, a reply goes from a server to a client */ 81 if (sport != IPPORT_BOOTPS || dport != IPPORT_BOOTPC) 82 printf(" (reply)"); 83 break; 84 85 default: 86 printf(" bootp-#%d", bp->bp_op); 87 } 88 89 TCHECK(bp->bp_secs); 90 91 /* The usual hardware address type is 1 (10Mb Ethernet) */ 92 if (bp->bp_htype != 1) 93 printf(" htype-#%d", bp->bp_htype); 94 95 /* The usual length for 10Mb Ethernet address is 6 bytes */ 96 if (bp->bp_htype != 1 || bp->bp_hlen != 6) 97 printf(" hlen:%d", bp->bp_hlen); 98 99 /* Only print interesting fields */ 100 if (bp->bp_hops) 101 printf(" hops:%d", bp->bp_hops); 102 if (bp->bp_xid) 103 printf(" xid:0x%x", (u_int32_t)ntohl(bp->bp_xid)); 104 if (bp->bp_secs) 105 printf(" secs:%d", ntohs(bp->bp_secs)); 106 if (bp->bp_flags) 107 printf(" flags:0x%x", ntohs(bp->bp_flags)); 108 109 /* Client's ip address */ 110 TCHECK(bp->bp_ciaddr); 111 if (bp->bp_ciaddr.s_addr) 112 printf(" C:%s", ipaddr_string(&bp->bp_ciaddr)); 113 114 /* 'your' ip address (bootp client) */ 115 TCHECK(bp->bp_yiaddr); 116 if (bp->bp_yiaddr.s_addr) 117 printf(" Y:%s", ipaddr_string(&bp->bp_yiaddr)); 118 119 /* Server's ip address */ 120 TCHECK(bp->bp_siaddr); 121 if (bp->bp_siaddr.s_addr) 122 printf(" S:%s", ipaddr_string(&bp->bp_siaddr)); 123 124 /* Gateway's ip address */ 125 TCHECK(bp->bp_giaddr); 126 if (bp->bp_giaddr.s_addr) 127 printf(" G:%s", ipaddr_string(&bp->bp_giaddr)); 128 129 /* Client's Ethernet address */ 130 if (bp->bp_htype == 1 && bp->bp_hlen == 6) { 131 register const struct ether_header *eh; 132 register const char *e; 133 134 TCHECK2(bp->bp_chaddr[0], 6); 135 eh = (struct ether_header *)packetp; 136 if (bp->bp_op == BOOTREQUEST) 137 e = (const char *)ESRC(eh); 138 else if (bp->bp_op == BOOTREPLY) 139 e = (const char *)EDST(eh); 140 else 141 e = 0; 142 if (e == 0 || memcmp((char *)bp->bp_chaddr, e, 6) != 0) 143 printf(" ether %s", etheraddr_string(bp->bp_chaddr)); 144 } 145 146 TCHECK2(bp->bp_sname[0], 1); /* check first char only */ 147 if (*bp->bp_sname) { 148 printf(" sname \""); 149 if (fn_print(bp->bp_sname, snapend)) { 150 putchar('"'); 151 fputs(tstr + 1, stdout); 152 return; 153 } 154 putchar('"'); 155 } 156 TCHECK2(bp->bp_sname[0], 1); /* check first char only */ 157 if (*bp->bp_file) { 158 printf(" file \""); 159 if (fn_print(bp->bp_file, snapend)) { 160 putchar('"'); 161 fputs(tstr + 1, stdout); 162 return; 163 } 164 putchar('"'); 165 } 166 167 /* Decode the vendor buffer */ 168 TCHECK(bp->bp_vend[0]); 169 length -= sizeof(*bp) - sizeof(bp->bp_vend); 170 if (memcmp((char *)bp->bp_vend, (char *)vm_rfc1048, 171 sizeof(u_int32_t)) == 0) 172 rfc1048_print(bp->bp_vend, length); 173 else if (memcmp((char *)bp->bp_vend, (char *)vm_cmu, 174 sizeof(u_int32_t)) == 0) 175 cmu_print(bp->bp_vend, length); 176 else { 177 u_int32_t ul; 178 179 ul = EXTRACT_32BITS(&bp->bp_vend); 180 if (ul != 0) 181 printf("vend-#0x%x", ul); 182 } 183 184 return; 185 trunc: 186 fputs(tstr, stdout); 187 } 188 189 /* The first character specifies the format to print */ 190 static struct tok tag2str[] = { 191 /* RFC1048 tags */ 192 { TAG_PAD, " PAD" }, 193 { TAG_SUBNET_MASK, "iSM" }, /* subnet mask (RFC950) */ 194 { TAG_TIME_OFFSET, "LTZ" }, /* seconds from UTC */ 195 { TAG_GATEWAY, "iDG" }, /* default gateway */ 196 { TAG_TIME_SERVER, "iTS" }, /* time servers (RFC868) */ 197 { TAG_NAME_SERVER, "iIEN" }, /* IEN name servers (IEN116) */ 198 { TAG_DOMAIN_SERVER, "iNS" }, /* domain name (RFC1035) */ 199 { TAG_LOG_SERVER, "iLOG" }, /* MIT log servers */ 200 { TAG_COOKIE_SERVER, "iCS" }, /* cookie servers (RFC865) */ 201 { TAG_LPR_SERVER, "iLPR" }, /* lpr server (RFC1179) */ 202 { TAG_IMPRESS_SERVER, "iIM" }, /* impress servers (Imagen) */ 203 { TAG_RLP_SERVER, "iRL" }, /* resource location (RFC887) */ 204 { TAG_HOSTNAME, "aHN" }, /* ascii hostname */ 205 { TAG_BOOTSIZE, "sBS" }, /* 512 byte blocks */ 206 { TAG_END, " END" }, 207 /* RFC1497 tags */ 208 { TAG_DUMPPATH, "aDP" }, 209 { TAG_DOMAINNAME, "aDN" }, 210 { TAG_SWAP_SERVER, "iSS" }, 211 { TAG_ROOTPATH, "aRP" }, 212 { TAG_EXTPATH, "aEP" }, 213 /* RFC2132 tags */ 214 { TAG_IP_FORWARD, "BIPF" }, 215 { TAG_NL_SRCRT, "BSRT" }, 216 { TAG_PFILTERS, "pPF" }, 217 { TAG_REASS_SIZE, "sRSZ" }, 218 { TAG_DEF_TTL, "bTTL" }, 219 { TAG_MTU_TIMEOUT, "lMA" }, 220 { TAG_MTU_TABLE, "sMT" }, 221 { TAG_INT_MTU, "sMTU" }, 222 { TAG_LOCAL_SUBNETS, "BLSN" }, 223 { TAG_BROAD_ADDR, "iBR" }, 224 { TAG_DO_MASK_DISC, "BMD" }, 225 { TAG_SUPPLY_MASK, "BMS" }, 226 { TAG_DO_RDISC, "BRD" }, 227 { TAG_RTR_SOL_ADDR, "iRSA" }, 228 { TAG_STATIC_ROUTE, "pSR" }, 229 { TAG_USE_TRAILERS, "BUT" }, 230 { TAG_ARP_TIMEOUT, "lAT" }, 231 { TAG_ETH_ENCAP, "BIE" }, 232 { TAG_TCP_TTL, "bTT" }, 233 { TAG_TCP_KEEPALIVE, "lKI" }, 234 { TAG_KEEPALIVE_GO, "BKG" }, 235 { TAG_NIS_DOMAIN, "aYD" }, 236 { TAG_NIS_SERVERS, "iYS" }, 237 { TAG_NTP_SERVERS, "iNTP" }, 238 { TAG_VENDOR_OPTS, "bVO" }, 239 { TAG_NETBIOS_NS, "iWNS" }, 240 { TAG_NETBIOS_DDS, "iWDD" }, 241 { TAG_NETBIOS_NODE, "bWNT" }, 242 { TAG_NETBIOS_SCOPE, "aWSC" }, 243 { TAG_XWIN_FS, "iXFS" }, 244 { TAG_XWIN_DM, "iXDM" }, 245 { TAG_NIS_P_DOMAIN, "sN+D" }, 246 { TAG_NIS_P_SERVERS, "iN+S" }, 247 { TAG_MOBILE_HOME, "iMH" }, 248 { TAG_SMPT_SERVER, "iSMTP" }, 249 { TAG_POP3_SERVER, "iPOP3" }, 250 { TAG_NNTP_SERVER, "iNNTP" }, 251 { TAG_WWW_SERVER, "iWWW" }, 252 { TAG_FINGER_SERVER, "iFG" }, 253 { TAG_IRC_SERVER, "iIRC" }, 254 { TAG_STREETTALK_SRVR, "iSTS" }, 255 { TAG_STREETTALK_STDA, "iSTDA" }, 256 { TAG_REQUESTED_IP, "iRQ" }, 257 { TAG_IP_LEASE, "lLT" }, 258 { TAG_OPT_OVERLOAD, "bOO" }, 259 { TAG_TFTP_SERVER, "aTFTP" }, 260 { TAG_BOOTFILENAME, "aBF" }, 261 { TAG_DHCP_MESSAGE, " DHCP" }, 262 { TAG_SERVER_ID, "iSID" }, 263 { TAG_PARM_REQUEST, "bPR" }, 264 { TAG_MESSAGE, "aMSG" }, 265 { TAG_MAX_MSG_SIZE, "sMSZ" }, 266 { TAG_RENEWAL_TIME, "lRN" }, 267 { TAG_REBIND_TIME, "lRB" }, 268 { TAG_VENDOR_CLASS, "bVC" }, 269 { TAG_CLIENT_ID, "xCID" }, 270 /* RFC 2485 */ 271 { TAG_OPEN_GROUP_UAP, "aUAP" }, 272 /* RFC 2563 */ 273 { TAG_DISABLE_AUTOCONF, "BNOAUTO" }, 274 /* RFC 2610 */ 275 { TAG_SLP_DA, "bSLP-DA" }, /*"b" is a little wrong */ 276 { TAG_SLP_SCOPE, "bSLP-SCOPE" }, /*"b" is a little wrong */ 277 /* RFC 2937 */ 278 { TAG_NS_SEARCH, "sNSSEARCH" }, /* XXX 's' */ 279 /* RFC 3011 */ 280 { TAG_IP4_SUBNET_SELECT, "iSUBNET" }, 281 /* ftp://ftp.isi.edu/.../assignments/bootp-dhcp-extensions */ 282 { TAG_USER_CLASS, "aCLASS" }, 283 { TAG_SLP_NAMING_AUTH, "aSLP-NA" }, 284 { TAG_CLIENT_FQDN, "bFQDN" }, /* XXX 'b' */ 285 { TAG_AGENT_CIRCUIT, "bACKT" }, 286 { TAG_AGENT_REMOTE, "bARMT" }, 287 { TAG_AGENT_MASK, "bAMSK" }, 288 { TAG_TZ_STRING, "aTZSTR" }, 289 { TAG_FQDN_OPTION, "bFQDNS" }, /* XXX 'b' */ 290 { TAG_AUTH, "bAUTH" }, /* XXX 'b' */ 291 { TAG_VINES_SERVERS, "iVINES" }, 292 { TAG_SERVER_RANK, "sRANK" }, 293 { TAG_CLIENT_ARCH, "sARCH" }, 294 { TAG_CLIENT_NDI, "bNDI" }, /* XXX 'b' */ 295 { TAG_CLIENT_GUID, "bGUID" }, /* XXX 'b' */ 296 { TAG_LDAP_URL, "aLDAP" }, 297 { TAG_6OVER4, "i6o4" }, 298 { TAG_PRINTER_NAME, "aPRTR" }, 299 { TAG_MDHCP_SERVER, "bMDHCP" }, /* XXX 'b' */ 300 { TAG_IPX_COMPAT, "bIPX" }, /* XXX 'b' */ 301 { TAG_NETINFO_PARENT, "iNI" }, 302 { TAG_NETINFO_PARENT_TAG, "aNITAG" }, 303 { TAG_URL, "aURL" }, 304 { TAG_FAILOVER, "bFAIL" }, /* XXX 'b' */ 305 { 0, NULL } 306 }; 307 /* 2-byte extended tags */ 308 static struct tok xtag2str[] = { 309 { 0, NULL } 310 }; 311 312 static void 313 rfc1048_print(register const u_char *bp, register u_int length) 314 { 315 register u_char tag; 316 register u_int len, size; 317 register const char *cp; 318 register char c; 319 int first; 320 u_int32_t ul; 321 u_short us; 322 323 printf(" vend-rfc1048"); 324 325 /* Step over magic cookie */ 326 bp += sizeof(int32_t); 327 328 /* Loop while we there is a tag left in the buffer */ 329 while (bp + 1 < snapend) { 330 tag = *bp++; 331 if (tag == TAG_PAD) 332 continue; 333 if (tag == TAG_END) 334 return; 335 if (tag == TAG_EXTENDED_OPTION) { 336 TCHECK2(*(bp + 1), 2); 337 tag = EXTRACT_16BITS(bp + 1); 338 /* XXX we don't know yet if the IANA will 339 * preclude overlap of 1-byte and 2-byte spaces. 340 * If not, we need to offset tag after this step. 341 */ 342 cp = tok2str(xtag2str, "?xT%d", tag); 343 } else 344 cp = tok2str(tag2str, "?T%d", tag); 345 c = *cp++; 346 printf(" %s:", cp); 347 348 /* Get the length; check for truncation */ 349 if (bp + 1 >= snapend) { 350 fputs(tstr, stdout); 351 return; 352 } 353 len = *bp++; 354 if (bp + len >= snapend) { 355 fputs(tstr, stdout); 356 return; 357 } 358 359 if (tag == TAG_DHCP_MESSAGE && len == 1) { 360 c = *bp++; 361 switch (c) { 362 case DHCPDISCOVER: printf("DISCOVER"); break; 363 case DHCPOFFER: printf("OFFER"); break; 364 case DHCPREQUEST: printf("REQUEST"); break; 365 case DHCPDECLINE: printf("DECLINE"); break; 366 case DHCPACK: printf("ACK"); break; 367 case DHCPNAK: printf("NACK"); break; 368 case DHCPRELEASE: printf("RELEASE"); break; 369 case DHCPINFORM: printf("INFORM"); break; 370 default: printf("%u", c); break; 371 } 372 continue; 373 } 374 375 if (tag == TAG_PARM_REQUEST) { 376 first = 1; 377 while (len-- > 0) { 378 c = *bp++; 379 cp = tok2str(tag2str, "?T%d", c); 380 if (!first) 381 putchar('+'); 382 printf("%s", cp + 1); 383 first = 0; 384 } 385 continue; 386 } 387 if (tag == TAG_EXTENDED_REQUEST) { 388 first = 1; 389 while (len > 1) { 390 len -= 2; 391 c = EXTRACT_16BITS(bp); 392 bp += 2; 393 cp = tok2str(xtag2str, "?xT%d", c); 394 if (!first) 395 putchar('+'); 396 printf("%s", cp + 1); 397 first = 0; 398 } 399 continue; 400 } 401 402 /* Print data */ 403 size = len; 404 if (c == '?') { 405 /* Base default formats for unknown tags on data size */ 406 if (size & 1) 407 c = 'b'; 408 else if (size & 2) 409 c = 's'; 410 else 411 c = 'l'; 412 } 413 first = 1; 414 switch (c) { 415 416 case 'a': 417 /* ascii strings */ 418 putchar('"'); 419 (void)fn_printn(bp, size, NULL); 420 putchar('"'); 421 bp += size; 422 size = 0; 423 break; 424 425 case 'i': 426 case 'l': 427 case 'L': 428 /* ip addresses/32-bit words */ 429 while (size >= sizeof(ul)) { 430 if (!first) 431 putchar(','); 432 ul = EXTRACT_32BITS(bp); 433 if (c == 'i') { 434 ul = htonl(ul); 435 printf("%s", ipaddr_string(&ul)); 436 } else if (c == 'L') 437 printf("%d", ul); 438 else 439 printf("%u", ul); 440 bp += sizeof(ul); 441 size -= sizeof(ul); 442 first = 0; 443 } 444 break; 445 446 case 'p': 447 /* IP address pairs */ 448 while (size >= 2*sizeof(ul)) { 449 if (!first) 450 putchar(','); 451 memcpy((char *)&ul, (char *)bp, sizeof(ul)); 452 printf("(%s:", ipaddr_string(&ul)); 453 bp += sizeof(ul); 454 memcpy((char *)&ul, (char *)bp, sizeof(ul)); 455 printf("%s)", ipaddr_string(&ul)); 456 bp += sizeof(ul); 457 size -= 2*sizeof(ul); 458 first = 0; 459 } 460 break; 461 462 case 's': 463 /* shorts */ 464 while (size >= sizeof(us)) { 465 if (!first) 466 putchar(','); 467 us = EXTRACT_16BITS(bp); 468 printf("%d", us); 469 bp += sizeof(us); 470 size -= sizeof(us); 471 first = 0; 472 } 473 break; 474 475 case 'B': 476 /* boolean */ 477 while (size > 0) { 478 if (!first) 479 putchar(','); 480 switch (*bp) { 481 case 0: 482 putchar('N'); 483 break; 484 case 1: 485 putchar('Y'); 486 break; 487 default: 488 printf("%d?", *bp); 489 break; 490 } 491 ++bp; 492 --size; 493 first = 0; 494 } 495 break; 496 497 case 'b': 498 case 'x': 499 default: 500 /* Bytes */ 501 while (size > 0) { 502 if (!first) 503 putchar (c == 'x' ? ':' : '.'); 504 printf (c == 'x' ? "%02x" : "%d", *bp); 505 ++bp; 506 --size; 507 first = 0; 508 } 509 break; 510 } 511 /* Data left over? */ 512 if (size) 513 printf("[len %d]", len); 514 } 515 return; 516 trunc: 517 printf("|[rfc1048]"); 518 } 519 520 static void 521 cmu_print(register const u_char *bp, register u_int length) 522 { 523 register const struct cmu_vend *cmu; 524 char *fmt = " %s:%s"; 525 526 #define PRINTCMUADDR(m, s) { TCHECK(cmu->m); \ 527 if (cmu->m.s_addr != 0) \ 528 printf(fmt, s, ipaddr_string(&cmu->m.s_addr)); } 529 530 printf(" vend-cmu"); 531 cmu = (struct cmu_vend *)bp; 532 533 /* Only print if there are unknown bits */ 534 TCHECK(cmu->v_flags); 535 if ((cmu->v_flags & ~(VF_SMASK)) != 0) 536 printf(" F:0x%x", cmu->v_flags); 537 PRINTCMUADDR(v_dgate, "DG"); 538 PRINTCMUADDR(v_smask, cmu->v_flags & VF_SMASK ? "SM" : "SM*"); 539 PRINTCMUADDR(v_dns1, "NS1"); 540 PRINTCMUADDR(v_dns2, "NS2"); 541 PRINTCMUADDR(v_ins1, "IEN1"); 542 PRINTCMUADDR(v_ins2, "IEN2"); 543 PRINTCMUADDR(v_ts1, "TS1"); 544 PRINTCMUADDR(v_ts2, "TS2"); 545 return; 546 547 trunc: 548 fputs(tstr, stdout); 549 #undef PRINTCMUADDR 550 } 551