/****************************************************************************
** File: ip.c
**
** Author: Mike Borella
**
** Comments: Dump IP header information
**
** $Id: ip.c,v 1.25 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 "global.h"
#include "ip_protocols.h"
#include "ip_services.h"
#define HOLDER_SIZE 64
/*
* Contains the descriptions of IP options
*/
strmap_t ip_option_map[] =
{
{ IP_OPTION_EOL, "end of options" },
{ IP_OPTION_NOP, "no op" },
{ IP_OPTION_RECORDROUTE, "record route" },
{ IP_OPTION_TIMESTAMP, "time stamp" },
{ IP_OPTION_TRACEROUTE, "traceroute" },
{ IP_OPTION_SECURITY, "security" },
{ IP_OPTION_LSR, "loose source route" },
{ IP_OPTION_EXTSECURITY, "extra security" },
{ IP_OPTION_COMSECURITY, "commercial security" },
{ IP_OPTION_STREAMID, "stream ID" },
{ IP_OPTION_SSR, "strict source route" },
{ IP_OPTION_ROUTERALERT, "router alert" },
{ 0, "" }
};
extern struct arg_t *my_args;
extern void (*ip_proto_func[])(packet_t *);
extern strmap_t ipproto_map[];
void dump_ip_options(packet_t *, u_int8_t);
/*----------------------------------------------------------------------------
**
** dump_ip()
**
** Parse IP header and dump fields
**
**----------------------------------------------------------------------------
*/
void dump_ip(packet_t *pkt)
{
ip_header_t ip;
u_int16_t frag_off;
u_int8_t ver, hlen;
u_int8_t u_bit, df_bit, mf_bit;
#ifdef DEBUG
printf("\nEntering IP\n");
#endif
/* Set the layer */
set_layer(LAYER_NETWORK);
/*
* Stats accounting
*/
stats_update(STATS_IP);
/*
* Get the IP header
*/
if (get_packet_bytes((u_int8_t *) &ip, pkt, sizeof(ip_header_t)) == 0)
return;
/*
* Conversions
*/
ver = ip.version;
hlen = ip.header_length;
ip.offset = ntohs(ip.offset);
ip.length = ntohs(ip.length);
ip.id = ntohs(ip.id);
frag_off = ip.offset & 0x1fff;
u_bit = (ip.offset & 0x8000) >> 15;
df_bit = (ip.offset & 0x4000) >> 14;
mf_bit = (ip.offset & 0x2000) >> 13;
ip.checksum = ntohs(ip.checksum);
/*
* Set the effective end of the packet. Take the total length as per the
* IP header, subtract the header we've read. This is the number of bytes
* into the packet where the end should be. This helps us get rid of
* link layer padding on tinygrams.
*/
set_packet_apparentend(pkt, ip.length - sizeof(ip_header_t));
/*
* Dump header
*/
if (my_args->m)
{
u_int16_t new_fo = frag_off * 8;
display_minimal_string("| IP ");
display_minimal_ipv4((u_int8_t *) &ip.src);
display_minimal_string("->");
display_minimal_ipv4((u_int8_t *) &ip.dst);
display_minimal_string(" (len:");
display_minimal((u_int8_t *) &ip.length, 2, DISP_DEC);
display_minimal_string(",id:");
display_minimal((u_int8_t *) &ip.id, 2, DISP_DEC);
if (df_bit)
display_minimal_string(",DF");
if (mf_bit)
display_minimal_string(",MF");
display_minimal_string(",frag:");
display_minimal((u_int8_t *) &new_fo, 2, DISP_DEC);
display_minimal_string(") ");
}
else
{
u_int8_t holder[64];
/* announcement */
display_header_banner("IP Header");
/* print fields */
display("Version", (u_int8_t *) &ver, 1, DISP_DEC);
sprintf(holder, "%d (%d bytes)", hlen, hlen*4);
display_string("Header length", holder);
display("TOS", (u_int8_t *) &ip.tos, 1, DISP_HEX);
display("Total length", (u_int8_t *) &ip.length, 2, DISP_DEC);
display("Identification", (u_int8_t *) &ip.id, 2, DISP_DEC);
if (frag_off)
{
sprintf(holder, "%d (%d bytes)", frag_off, frag_off*8);
display_string("Fragmentation offset", holder);
}
else
display("Fragmentation offset", (u_int8_t *) &frag_off, 2, DISP_DEC);
display("Unused bit", (u_int8_t *) &u_bit, 1, DISP_BINNLZ);
display("Don't fragment bit", (u_int8_t *) &df_bit, 1, DISP_BINNLZ);
display("More fragments bit", (u_int8_t *) &mf_bit, 1, DISP_BINNLZ);
display("Time to live", (u_int8_t *) &ip.ttl, 1, DISP_DEC);
display_strmap("Protocol", ip.protocol, ipproto_map);
display("Header checksum", (u_int8_t *) &ip.checksum, 2,
DISP_DEC);
/* IP's are not in network byte order?? */
display_ipv4("Source address", (u_int8_t *) &ip.src);
display_ipv4("Destination address", (u_int8_t *) &ip.dst);
}
/* set IP address state */
state_set_srcaddr(ntohl(ip.src));
state_set_dstaddr(ntohl(ip.dst));
/* check for IP options */
if (hlen > 5)
dump_ip_options(pkt, hlen * 4 - 20);
/* dump the hex buffer */
hexbuffer_flush();
/*
* If this is fragment zero, hand it to the next higher
* level protocol.
*/
if ((ip.offset & 0x1fff) == 0 && ip_proto_func[ip.protocol])
ip_proto_func[ip.protocol](pkt);
#ifdef DEBUG
printf("\nLeaving IP\n");
#endif
}
/*----------------------------------------------------------------------------
**
** dump_ip_recordroute()
**
** Dump a record route IP option
**
**----------------------------------------------------------------------------
*/
void dump_ip_recordroute(u_int8_t * rr, u_int8_t len)
{
u_int8_t pointer;
u_int32_t addr;
int i;
/*
* The first byte should be a pointer and the next len-1 bytes should be
* a series of IP addresses. If len-1 is not a multiple of 4 then something
* is very wrong and we bail out.
*/
pointer = *rr;
if (!my_args->m)
{
display(" Pointer", (u_int8_t *) &pointer, 1, DISP_HEX);
}
i = 1;
while (i+3 <= len)
{
/* Get and address then increment i to the next address */
memcpy((u_int8_t *) &addr, rr+i, 4);
display_ipv4(" Address", (u_int8_t *) &addr);
i = i + 4;
}
}
/*----------------------------------------------------------------------------
**
** dump_ip_options()
**
** Dump any IP options
**
**----------------------------------------------------------------------------
*/
void dump_ip_options(packet_t *pkt, u_int8_t length)
{
u_int8_t bytes_read = 0;
ip_option_t opt;
char holder[HOLDER_SIZE];
while(bytes_read < length)
{
/*
* Get the first byte to make sure that we don't have a 1-byte option
*/
if (get_packet_bytes((u_int8_t *) &opt.code, pkt, 1) == 0)
return;
bytes_read += 1;
/*
* Display it
*/
snprintf(holder, HOLDER_SIZE, "%d (%s)", opt.code,
map2str(ip_option_map, opt.code));
if (!my_args->m)
display_string("IP option code", holder);
else
{
display_minimal_string(holder);
display_minimal_string(" ");
}
/*
* If it is 0, then its just a 1-byte EOL
*/
if (opt.code == 0)
continue;
/*
* It isn't, so lets read the rest...
*/
if (get_packet_bytes((u_int8_t *) &opt.length, pkt, 1) == 0)
return;
bytes_read += 1;
if (!my_args->m)
display(" Length", (u_int8_t *) &opt.length, 1, DISP_DEC);
/*
* Get the rest of the option, adjusting the length by 2 to count
* option type and length fields...
*/
if (get_packet_bytes((u_int8_t *) &holder, pkt, opt.length-2) == 0)
return;
bytes_read = bytes_read + opt.length - 2;
/*
* Do something intelligent with the options that we understand
*/
switch(opt.code)
{
case IP_OPTION_RECORDROUTE:
dump_ip_recordroute(holder, opt.length-2);
break;
default:
break;
}
}
}
syntax highlighted by Code2HTML, v. 0.9.1