/**************************************************************************** ** File: dhcp.c ** ** Author: Mike Borella ** ** Comments: Dump DHCP header information. See RFCs 2131 and 2132. ** ** $Id: dhcp.c,v 1.15 2002/01/03 00:04:01 mborella Exp $ ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU Library General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ** *****************************************************************************/ #include "arp.h" #include "dhcp.h" #define HOLDER_SIZE 256 /* * DHCP operation type map */ strmap_t dhcp_op_map[] = { { DHCP_OP_BOOTREQUEST, "boot request" }, { DHCP_OP_BOOTREPLY, "boot reply" }, { 0, "" } }; /* * DHCP option map */ strmap_t dhcp_option_map[] = { { DHCP_OPTION_PAD, "pad" }, { DHCP_OPTION_NETMASK, "netmask" }, { DHCP_OPTION_TIMEOFFSET, "time offset" }, { DHCP_OPTION_ROUTER, "router" }, { DHCP_OPTION_TIMESERVER, "time server" }, { DHCP_OPTION_NAMESERVER, "name server" }, { DHCP_OPTION_DNS, "DNS server" }, { DHCP_OPTION_LOGSERVER, "log server" }, { DHCP_OPTION_COOKIESERVER, "cookie server" }, { DHCP_OPTION_LPRSERVER, "LPR server" }, { DHCP_OPTION_IMPRESSSERVER, "impress server" }, { DHCP_OPTION_RESLOCSERVER, "RLP server" }, { DHCP_OPTION_HOSTNAME, "hostname" }, { DHCP_OPTION_BOOTFILESIZE, "boot file size" }, { DHCP_OPTION_MERITDUMP, "Merit dump" }, { DHCP_OPTION_DOMAINNAME, "domain name" }, { DHCP_OPTION_SWAPSERVER, "swap server" }, { DHCP_OPTION_ROOTPATH, "root path" }, { DHCP_OPTION_EXTSPATH, "extension path" }, { DHCP_OPTION_IPFORWARD, "IP forward" }, { DHCP_OPTION_NONLOCALSR, "source routing" }, { DHCP_OPTION_POLICYFILTER, "policy filter" }, { DHCP_OPTION_VENDORSPECIFIC, "vendor specific" }, { DHCP_OPTION_NETBIOSNAMESERV, "NETBIOS name server" }, { DHCP_OPTION_NETBIOSDGDIST, "NETBIOS datagram distribution server" }, { DHCP_OPTION_NETBIOSNODETYPE, "NETBIOS node type" }, { DHCP_OPTION_NETBIOSSCOPE, "NETBIOS scope" }, { DHCP_OPTION_REQUESTEDIPADDR, "requested IP address" }, { DHCP_OPTION_IPADDRLEASE, "IP address lease" }, { DHCP_OPTION_OVERLOAD, "overload" }, { DHCP_OPTION_MESSAGETYPE, "message type" }, { DHCP_OPTION_SERVERID, "server ID" }, { DHCP_OPTION_PARAMREQLIST, "parameter request list" }, { DHCP_OPTION_RENEWALTIME, "renewal time" }, { DHCP_OPTION_REBINDINGTIME, "rebinding time" }, { DHCP_OPTION_VENDORCLASSID, "vendor class ID" }, { DHCP_OPTION_CLIENTID, "client ID" }, { DHCP_OPTION_USERCLASS, "user class" }, { DHCP_OPTION_END, "end of options" }, { 0, "" } }; /* * DHCP message type map */ strmap_t dhcp_msgtype_map[] = { { DHCP_MSGTYPE_DISCOVER, "DHCPDISCOVER" }, { DHCP_MSGTYPE_OFFER, "DHCPOFFER" }, { DHCP_MSGTYPE_REQUEST, "DHCPREQUEST" }, { DHCP_MSGTYPE_DECLINE, "DHCPDECLINE" }, { DHCP_MSGTYPE_ACK, "DHCPACK" }, { DHCP_MSGTYPE_NAK, "DHCPNAK" }, { DHCP_MSGTYPE_RELEASE, "DHCPRELASE" }, { DHCP_MSGTYPE_INFORM, "DHCPINFORM" }, { 0, "" } }; extern struct arg_t *my_args; extern strmap_t arp_hardware_map[]; /*---------------------------------------------------------------------------- ** ** dump_dhcp() ** ** Parse DHCP packet and dump fields ** **---------------------------------------------------------------------------- */ void dump_dhcp(packet_t *pkt) { dhcp_header_t dhcp; int j; u_int32_t i; u_int32_t cookie_holder; u_int8_t opt; char holder[HOLDER_SIZE]; /* this needs to be as big as the biggest option */ /* Set the layer */ set_layer(LAYER_APPLICATION); /* * Get the DHCP fixed header */ if (get_packet_bytes((u_int8_t *) &dhcp, pkt, sizeof(dhcp_header_t)) == 0) return; /* * Conversions */ dhcp.xid = ntohl(dhcp.xid); dhcp.secs = ntohs(dhcp.secs); dhcp.flags = ntohs(dhcp.flags); /* announcement */ if (!my_args->m) display_header_banner("DHCP Header"); /* * Display operation, other info */ snprintf(holder, HOLDER_SIZE, "%d (%s)", dhcp.op, map2str(dhcp_op_map, dhcp.op)); if (my_args->m) { display_minimal_string(map2str(dhcp_op_map, dhcp.op)); display_minimal_string(" "); } else { display("Operation", (u_int8_t *) holder, strlen(holder), DISP_STRING); display("Hardware addr type", (u_int8_t *) &dhcp.htype, 1, DISP_DEC); display("Hardware addr length", (u_int8_t *) &dhcp.hlen, 1, DISP_DEC); display("Hops", (u_int8_t *) &dhcp.hops, 1, DISP_DEC); display("Transaction ID", (u_int8_t *) &dhcp.xid, 4, DISP_HEX); display("Seconds", (u_int8_t *) &dhcp.secs, 2, DISP_DEC); display("Flags", (u_int8_t *) &dhcp.flags, 2, DISP_HEX); } /* * Display IPs */ if (!my_args->m) { display_ipv4("Client addr", (u_int8_t *) &dhcp.ciaddr); display_ipv4("Your addr", (u_int8_t *) &dhcp.yiaddr); display_ipv4("Next server addr", (u_int8_t *) &dhcp.siaddr); display_ipv4("Relay agent addr", (u_int8_t *) &dhcp.giaddr); printf("Client hardware addr: \n"); } /* * Display names */ if (!my_args->m) { display("Server host name", (u_int8_t *) dhcp.sname, strlen(dhcp.sname), DISP_STRING); display("Boot file name", (u_int8_t *) dhcp.file, strlen(dhcp.file), DISP_STRING); } /* * Look for BOOTP cookie */ i = htonl(BOOTP_COOKIE); if (look_packet_bytes((u_int8_t *) &cookie_holder, pkt, 4) == 0) return; if (i == cookie_holder && !my_args->m) { if (skip_packet_bytes(pkt, 4) == 0) return; display("BOOTP cookie", (u_int8_t *) &cookie_holder, 4, DISP_HEX); } /* * Parse the options list */ while (get_packet_apparentbytesleft(pkt)) { u_int8_t len=0; /* * Get the option number and dump it */ if (get_packet_bytes((u_int8_t *) &opt, pkt, 1) == 0) return; snprintf(holder, HOLDER_SIZE, "%d (%s)", opt, map2str(dhcp_option_map, opt)); if (!my_args->m) display("Option", (u_int8_t *) holder, strlen(holder), DISP_STRING); /* * If its a pad, go back and get another */ if (opt == DHCP_OPTION_PAD) continue; /* * If its an end-of-options indicator, bail out */ if (opt == DHCP_OPTION_END) break; /* * Otherwise, grab and dump the length */ if (get_packet_bytes((u_int8_t *) &len, pkt, 1) == 0) return; if (!my_args->m) display(" Length", (u_int8_t *) &len, 1, DISP_DEC); switch(opt) { case DHCP_OPTION_NETMASK: /* 1 */ if (get_packet_bytes((u_int8_t *) holder, pkt, len) == 0) return; if (!my_args->m) display_ipv4(" Mask", (u_int8_t *) holder); break; case DHCP_OPTION_TIMEOFFSET: /* 2 */ if (get_packet_bytes((u_int8_t *) holder, pkt, len) == 0) return; if (!my_args->m) display(" Offset", (u_int8_t *) holder, len, DISP_DEC); break; case DHCP_OPTION_ROUTER: /* 3 */ case DHCP_OPTION_TIMESERVER: /* 4 */ case DHCP_OPTION_NAMESERVER: /* 5 */ case DHCP_OPTION_DNS: /* 6 */ case DHCP_OPTION_NETBIOSNAMESERV: /* 44 */ j = 0; while (j < len / 4) { if (get_packet_bytes((u_int8_t *) holder, pkt, 4) == 0) return; if (!my_args->m) display_ipv4(" Address", (u_int8_t *) holder); j++; } break; case DHCP_OPTION_HOSTNAME: /* 12 */ if (get_packet_bytes((u_int8_t *) holder, pkt, len) == 0) return; holder[len] = '\0'; if (!my_args->m) display(" Host name", (u_int8_t *) holder, strlen(holder), DISP_STRING); break; case DHCP_OPTION_DOMAINNAME: /* 15 */ if (get_packet_bytes((u_int8_t *) holder, pkt, len) == 0) return; holder[len] = '\0'; if (!my_args->m) display(" Domain name", (u_int8_t *) holder, strlen(holder), DISP_STRING); break; case DHCP_OPTION_VENDORSPECIFIC: /* 43 */ if (get_packet_bytes((u_int8_t *) holder, pkt, len) == 0) return; if (!my_args->m) display(" Parameters", (u_int8_t *) holder, len, DISP_HEX); break; case DHCP_OPTION_NETBIOSNODETYPE: /* 46 */ if (get_packet_bytes((u_int8_t *) holder, pkt, len) == 0) return; switch(holder[0]) { case 0x1: snprintf(holder, HOLDER_SIZE, "0x%x (B-node / broadcast)", holder[0]); break; case 0x2: snprintf(holder, HOLDER_SIZE, "0x%x (P-node / point to point)", holder[0]); break; case 0x4: snprintf(holder, HOLDER_SIZE, "0x%x (M-node / mixed)", holder[0]); break; case 0x8: snprintf(holder, HOLDER_SIZE, "0x%x (H-node)", holder[0]); break; } if (!my_args->m) display_string("Node type", holder); break; case DHCP_OPTION_REQUESTEDIPADDR: /* 50 */ if (get_packet_bytes((u_int8_t *) holder, pkt, len) == 0) return; if (!my_args->m) display_ipv4(" Address", (u_int8_t *) holder); else { display_minimal_ipv4((u_int8_t *) holder); display_minimal_string(" "); } break; case DHCP_OPTION_IPADDRLEASE: /* 51 */ if (get_packet_bytes((u_int8_t *) holder, pkt, 4) == 0) return; if (!my_args->m) display(" Lease time", (u_int8_t *) holder, 4, DISP_DEC); break; case DHCP_OPTION_MESSAGETYPE: /* 53 */ { u_int8_t msg_type; if (get_packet_bytes(&msg_type, pkt, 1) == 0) return; snprintf(holder, HOLDER_SIZE, "%d (%s)", msg_type, map2str(dhcp_msgtype_map, msg_type)); if (!my_args->m) display_string(" Message type", holder); else { display_minimal_string(map2str(dhcp_msgtype_map, msg_type)); display_minimal_string(" "); } } break; case DHCP_OPTION_SERVERID: /* 54 */ if (get_packet_bytes((u_int8_t *) holder, pkt, len) == 0) return; if (!my_args->m) display_ipv4(" Address", (u_int8_t *) holder); break; case DHCP_OPTION_PARAMREQLIST: /* 55 */ for (i=0; i < len; i++) { u_int8_t opt; if (get_packet_bytes((u_int8_t *) &opt, pkt, 1) == 0) return; if (!my_args->m) { snprintf(holder, HOLDER_SIZE, "%d (%s)", opt, map2str(dhcp_option_map, opt)); display_string(" Option", holder); } } break; case DHCP_OPTION_MAXDHCPMSGSIZE: /* 57 */ if (get_packet_bytes((u_int8_t *) holder, pkt, len) == 0) return; if (!my_args->m) display(" Size", (u_int8_t *) holder, 2, DISP_DEC); break; case DHCP_OPTION_RENEWALTIME: /* 58 */ { u_int32_t renewal_time; if (get_packet_bytes((u_int8_t *) &renewal_time, pkt, len) == 0) return; renewal_time = ntohl(renewal_time); if (!my_args->m) display(" Renewal time", (u_int8_t *) &renewal_time, 4, DISP_DEC); } break; case DHCP_OPTION_REBINDINGTIME: /* 59 */ { u_int32_t rebinding_time; if (get_packet_bytes((u_int8_t *) &rebinding_time, pkt, len) == 0) return; rebinding_time = ntohl(rebinding_time); if (!my_args->m) display(" Rebinding time", (u_int8_t *) &rebinding_time, 4, DISP_DEC); } break; case DHCP_OPTION_VENDORCLASSID: /* 60 */ if (get_packet_bytes((u_int8_t *) holder, pkt, len) == 0) return; if (!my_args->m) display(" Parameters", (u_int8_t *) holder, len, DISP_HEX); break; case DHCP_OPTION_CLIENTID: /* 61 */ if (!my_args->m) { u_int8_t hw_type; /* The first byte should be a hardware type */ if (get_packet_bytes((u_int8_t *) &hw_type, pkt, 1) == 0) return; snprintf(holder, HOLDER_SIZE, "%d (%s)", hw_type, map2str(arp_hardware_map, hw_type)); display_string(" Hardware type", (u_int8_t *) holder); /* If its ethernet, display it as such, otherwise punt */ if (hw_type == ARP_HWTYPE_ETHERNET) { if (get_packet_bytes((u_int8_t *) holder, pkt, len-1) == 0) return; display(" Hardware address", (u_int8_t *) holder, len-1, DISP_HEXCOLONS); } else { if (get_packet_bytes((u_int8_t *) holder, pkt, len-1) == 0) return; display(" Hardware address", (u_int8_t *) holder, len-1, DISP_HEX); } } else { /* In minimal mode, we'll just grab the parameter and continue */ if (get_packet_bytes((u_int8_t *) holder, pkt, len) == 0) return; } break; default: break; /* do nothing for now */ } /* switch */ } /* while */ /* dump the hex buffer */ hexbuffer_flush(); }