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