/****************************************************************************
** 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();
}
syntax highlighted by Code2HTML, v. 0.9.1