print-bootp.c revision 1.8
1/* 2 * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996 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 24static const char rcsid[] = 25 "@(#) $Header: /usr/local/opengrok/home/cvs-mirror/mirrors/openbsd/src/usr.sbin/tcpdump/print-bootp.c,v 1.8 1999/07/28 20:41:36 jakob Exp $ (LBL)"; 26#endif 27 28#include <sys/param.h> 29#include <sys/time.h> 30#include <sys/socket.h> 31 32#ifdef __STDC__ 33struct mbuf; 34struct rtentry; 35#endif 36#include <net/if.h> 37 38#include <netinet/in.h> 39#include <netinet/if_ether.h> 40 41#include <ctype.h> 42#include <memory.h> 43#include <stdio.h> 44#include <string.h> 45 46#include "interface.h" 47#include "addrtoname.h" 48#include "bootp.h" 49 50static void rfc1048_print(const u_char *, u_int); 51static void cmu_print(const u_char *, u_int); 52 53static char tstr[] = " [|bootp]"; 54 55/* 56 * Print bootp requests 57 */ 58void 59bootp_print(register const u_char *cp, u_int length, 60 u_short sport, u_short dport) 61{ 62 register const struct bootp *bp; 63 static u_char vm_cmu[4] = VM_CMU; 64 static u_char vm_rfc1048[4] = VM_RFC1048; 65 66 bp = (struct bootp *)cp; 67 TCHECK(bp->bp_op); 68 switch (bp->bp_op) { 69 70 case BOOTREQUEST: 71 /* Usually, a request goes from a client to a server */ 72 if (sport != IPPORT_BOOTPC || dport != IPPORT_BOOTPS) 73 printf(" (request)"); 74 break; 75 76 case BOOTREPLY: 77 /* Usually, a reply goes from a server to a client */ 78 if (sport != IPPORT_BOOTPS || dport != IPPORT_BOOTPC) 79 printf(" (reply)"); 80 break; 81 82 default: 83 printf(" bootp-#%d", bp->bp_op); 84 } 85 86 TCHECK(bp->bp_secs); 87 88 /* The usual hardware address type is 1 (10Mb Ethernet) */ 89 if (bp->bp_htype != 1) 90 printf(" htype-#%d", bp->bp_htype); 91 92 /* The usual length for 10Mb Ethernet address is 6 bytes */ 93 if (bp->bp_htype != 1 || bp->bp_hlen != 6) 94 printf(" hlen:%d", bp->bp_hlen); 95 96 /* Only print interesting fields */ 97 if (bp->bp_hops) 98 printf(" hops:%d", bp->bp_hops); 99 if (bp->bp_xid) 100 printf(" xid:0x%x", (u_int32_t)ntohl(bp->bp_xid)); 101 if (bp->bp_secs) 102 printf(" secs:%d", ntohs(bp->bp_secs)); 103 104 /* Client's ip address */ 105 TCHECK(bp->bp_ciaddr); 106 if (bp->bp_ciaddr.s_addr) 107 printf(" C:%s", ipaddr_string(&bp->bp_ciaddr)); 108 109 /* 'your' ip address (bootp client) */ 110 TCHECK(bp->bp_yiaddr); 111 if (bp->bp_yiaddr.s_addr) 112 printf(" Y:%s", ipaddr_string(&bp->bp_yiaddr)); 113 114 /* Server's ip address */ 115 TCHECK(bp->bp_siaddr); 116 if (bp->bp_siaddr.s_addr) 117 printf(" S:%s", ipaddr_string(&bp->bp_siaddr)); 118 119 /* Gateway's ip address */ 120 TCHECK(bp->bp_giaddr); 121 if (bp->bp_giaddr.s_addr) 122 printf(" G:%s", ipaddr_string(&bp->bp_giaddr)); 123 124 /* Client's Ethernet address */ 125 if (bp->bp_htype == 1 && bp->bp_hlen == 6) { 126 register const struct ether_header *eh; 127 register const char *e; 128 129 TCHECK2(bp->bp_chaddr[0], 6); 130 eh = (struct ether_header *)packetp; 131 if (bp->bp_op == BOOTREQUEST) 132 e = (const char *)ESRC(eh); 133 else if (bp->bp_op == BOOTREPLY) 134 e = (const char *)EDST(eh); 135 else 136 e = 0; 137 if (e == 0 || memcmp((char *)bp->bp_chaddr, e, 6) != 0) 138 printf(" ether %s", etheraddr_string(bp->bp_chaddr)); 139 } 140 141 TCHECK2(bp->bp_sname[0], 1); /* check first char only */ 142 if (*bp->bp_sname) { 143 printf(" sname \""); 144 if (fn_print(bp->bp_sname, snapend)) { 145 putchar('"'); 146 fputs(tstr + 1, stdout); 147 return; 148 } 149 putchar('"'); 150 } 151 TCHECK2(bp->bp_file[0], 1); /* check first char only */ 152 if (*bp->bp_file) { 153 printf(" file \""); 154 if (fn_print(bp->bp_file, snapend)) { 155 putchar('"'); 156 fputs(tstr + 1, stdout); 157 return; 158 } 159 putchar('"'); 160 } 161 162 /* Decode the vendor buffer */ 163 TCHECK(bp->bp_vend[0]); 164 length -= sizeof(*bp) - sizeof(bp->bp_vend); 165 if (memcmp((char *)bp->bp_vend, (char *)vm_rfc1048, 166 sizeof(u_int32_t)) == 0) 167 rfc1048_print(bp->bp_vend, length); 168 else if (memcmp((char *)bp->bp_vend, (char *)vm_cmu, 169 sizeof(u_int32_t)) == 0) 170 cmu_print(bp->bp_vend, length); 171 else { 172 u_int32_t ul; 173 174 memcpy((char *)&ul, (char *)bp->bp_vend, sizeof(ul)); 175 if (ul != 0) 176 printf("vend-#0x%x", ul); 177 } 178 179 return; 180trunc: 181 fputs(tstr, stdout); 182} 183 184/* The first character specifies the format to print */ 185static struct tok tag2str[] = { 186/* RFC1048 tags */ 187 { TAG_PAD, " PAD" }, 188 { TAG_SUBNET_MASK, "iSM" }, /* subnet mask (RFC950) */ 189 { TAG_TIME_OFFSET, "lTZ" }, /* seconds from UTC */ 190 { TAG_GATEWAY, "iDG" }, /* default gateway */ 191 { TAG_TIME_SERVER, "iTS" }, /* time servers (RFC868) */ 192 { TAG_NAME_SERVER, "iIEN" }, /* IEN name servers (IEN116) */ 193 { TAG_DOMAIN_SERVER, "iNS" }, /* domain name (RFC1035) */ 194 { TAG_LOG_SERVER, "iLOG" }, /* MIT log servers */ 195 { TAG_COOKIE_SERVER, "iCS" }, /* cookie servers (RFC865) */ 196 { TAG_LPR_SERVER, "iLPR" }, /* lpr server (RFC1179) */ 197 { TAG_IMPRESS_SERVER, "iIM" }, /* impress servers (Imagen) */ 198 { TAG_RLP_SERVER, "iRL" }, /* resource location (RFC887) */ 199 { TAG_HOSTNAME, "aHN" }, /* ascii hostname */ 200 { TAG_BOOTSIZE, "sBS" }, /* 512 byte blocks */ 201 { TAG_END, " END" }, 202/* RFC1497 tags */ 203 { TAG_DUMPPATH, "aDP" }, 204 { TAG_DOMAINNAME, "aDN" }, 205 { TAG_SWAP_SERVER, "iSS" }, 206 { TAG_ROOTPATH, "aRP" }, 207 { TAG_EXTPATH, "aEP" }, 208 { 0, NULL } 209}; 210 211static void 212rfc1048_print(register const u_char *bp, register u_int length) 213{ 214 register u_char tag; 215 register u_int len, size; 216 register const char *cp; 217 register char c; 218 int first; 219 u_int32_t ul; 220 u_short us; 221 222 printf(" vend-rfc1048"); 223 224 /* Step over magic cookie */ 225 bp += sizeof(int32_t); 226 227 /* Loop while we there is a tag left in the buffer */ 228 while (bp + 1 < snapend) { 229 tag = *bp++; 230 if (tag == TAG_PAD) 231 continue; 232 if (tag == TAG_END) 233 return; 234 cp = tok2str(tag2str, "?T%d", tag); 235 c = *cp++; 236 printf(" %s:", cp); 237 238 /* Get the length; check for truncation */ 239 if (bp + 1 >= snapend) { 240 fputs(tstr, stdout); 241 return; 242 } 243 len = *bp++; 244 if (bp + len >= snapend) { 245 fputs(tstr, stdout); 246 return; 247 } 248 249 /* Print data */ 250 size = len; 251 if (c == '?') { 252 /* Base default formats for unknown tags on data size */ 253 if (size & 1) 254 c = 'b'; 255 else if (size & 2) 256 c = 's'; 257 else 258 c = 'l'; 259 } 260 first = 1; 261 switch (c) { 262 263 case 'a': 264 /* ascii strings */ 265 putchar('"'); 266 (void)fn_printn(bp, size, NULL); 267 putchar('"'); 268 bp += size; 269 size = 0; 270 break; 271 272 case 'i': 273 case 'l': 274 /* ip addresses/32-bit words */ 275 while (size >= sizeof(ul)) { 276 if (!first) 277 putchar(','); 278 memcpy((char *)&ul, (char *)bp, sizeof(ul)); 279 if (c == 'i') 280 printf("%s", ipaddr_string(&ul)); 281 else 282 printf("%u", ul); 283 bp += sizeof(ul); 284 size -= sizeof(ul); 285 first = 0; 286 } 287 break; 288 289 case 's': 290 /* shorts */ 291 while (size >= sizeof(us)) { 292 if (!first) 293 putchar(','); 294 memcpy((char *)&us, (char *)bp, sizeof(us)); 295 printf("%d", us); 296 bp += sizeof(us); 297 size -= sizeof(us); 298 first = 0; 299 } 300 break; 301 302 case 'b': 303 default: 304 /* Bytes */ 305 while (size > 0) { 306 if (!first) 307 putchar('.'); 308 printf("%d", *bp); 309 ++bp; 310 --size; 311 first = 0; 312 } 313 break; 314 } 315 /* Data left over? */ 316 if (size) 317 printf("[len %d]", len); 318 } 319} 320 321static void 322cmu_print(register const u_char *bp, register u_int length) 323{ 324 register const struct cmu_vend *cmu; 325 char *fmt = " %s:%s"; 326 327#define PRINTCMUADDR(m, s) { TCHECK(cmu->m); \ 328 if (cmu->m.s_addr != 0) \ 329 printf(fmt, s, ipaddr_string(&cmu->m.s_addr)); } 330 331 printf(" vend-cmu"); 332 cmu = (struct cmu_vend *)bp; 333 334 /* Only print if there are unknown bits */ 335 TCHECK(cmu->v_flags); 336 if ((cmu->v_flags & ~(VF_SMASK)) != 0) 337 printf(" F:0x%x", cmu->v_flags); 338 PRINTCMUADDR(v_dgate, "DG"); 339 PRINTCMUADDR(v_smask, cmu->v_flags & VF_SMASK ? "SM" : "SM*"); 340 PRINTCMUADDR(v_dns1, "NS1"); 341 PRINTCMUADDR(v_dns2, "NS2"); 342 PRINTCMUADDR(v_ins1, "IEN1"); 343 PRINTCMUADDR(v_ins2, "IEN2"); 344 PRINTCMUADDR(v_ts1, "TS1"); 345 PRINTCMUADDR(v_ts2, "TS2"); 346 return; 347 348trunc: 349 fputs(tstr, stdout); 350#undef PRINTCMUADDR 351} 352