/**************************************************************************** ** 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; } } }