/**************************************************************************** ** File: gre.c ** ** Author: Mike Borella ** ** Comments: ** ** $Id: gre.c,v 1.12 2001/11/15 00:22:36 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 "gre.h" #include "ip_protocols.h" #include "ethertypes.h" extern struct arg_t * my_args; extern strmap_t ipproto_map[]; extern strmap_t ethertype_map[]; /*---------------------------------------------------------------------------- ** ** dump_gre() ** ** Displays both versions of GRE headers ** **---------------------------------------------------------------------------- */ void dump_gre(packet_t *pkt) { gre_v0_rfc2784_t gre0; gre_v1_t gre1; ethertype_func_t et; /* Set the layer */ set_layer(LAYER_NETWORK); /* * Stats accounting */ stats_update(STATS_GRE); /* * Look at the first 2 bytes of the GRE header so that we can check the * version */ if (look_packet_bytes((u_int8_t *) &gre0, pkt, 2) == 0) return; /* * Check version number */ switch(gre0.version) { case 0: { u_int16_t reserved; u_int16_t protocol; ethertype_func_t et; /* * Please note: If the reserved field is 0, we assume that * the GRE packet follows RFC2784 and act accordingly. Otherwise * we assume the RFC1701 interpretation. If key and sequence * number fields are used, ala RFC2890, then we parse according * RFC1701. Got all that? */ reserved = (gre0.reserved_high << 5) || gre0.reserved_low; protocol = ntohs(gre0.protocol); if (reserved == 0) { gre_v0_rfc2784_t gre; u_int8_t C; /* * Get the header */ if (get_packet_bytes((u_int8_t *) &gre, pkt, sizeof(gre_v0_rfc2784_t)) == 0) return; /* * Conversions */ gre.protocol = ntohs(gre.protocol); protocol = gre.protocol; C = gre.c; /* Dump the header */ if (my_args->m) { display_minimal_string("| GRE v0 "); display_minimal((u_int8_t *) &gre.protocol, 2, DISP_HEX); } else { display_header_banner("GREv0 Header"); display("C", &C, 1, DISP_DEC); display("Reserved", (u_int8_t *) &reserved, 2, DISP_DEC); display_strmap_hex("Protocol", gre.protocol, ethertype_map); } /* * Get the checksum and reserved fields, if they exist */ if (C) { u_int16_t checksum; u_int16_t reserved; /* Get the fields */ if (get_packet_bytes((u_int8_t *) &checksum, pkt, 2) == 0) return; if (get_packet_bytes((u_int8_t *) &reserved, pkt, 2) == 0) return; /* conversions */ checksum = ntohs(checksum); reserved = ntohs(reserved); if (!my_args->m) { display("Checksum", (u_int8_t *) &checksum, 2, DISP_DEC); display("Reserved", (u_int8_t *) &reserved, 2, DISP_DEC); } } } else { gre_v0_rfc1701_t gre; u_int8_t C, R, K, S, s, recur, flags, version; /* * Get the header */ if (get_packet_bytes((u_int8_t *) &gre, pkt, sizeof(gre_v0_rfc1701_t)) == 0) return; /* * Conversions */ gre.protocol = ntohs(gre.protocol); protocol = gre.protocol; C = gre.c; R = gre.r; K = gre.k; S = gre.S; s = gre.s; recur = gre.recur; flags = gre.flags; version = gre.version; /* Dump the header */ if (my_args->m) { display_minimal_string("| GRE v0 "); display_minimal((u_int8_t *) &gre.protocol, 2, DISP_HEX); display_minimal_string(" "); } else { display_header_banner("GREv0 Header"); display("C", &C, 1, DISP_DEC); display("R", &R, 1, DISP_DEC); display("K", &K, 1, DISP_DEC); display("S", &S, 1, DISP_DEC); display("s", &s, 1, DISP_DEC); display("Recur", &recur, 1, DISP_DEC); display("Flags", &flags, 1, DISP_DEC); display("Version", &version, 1, DISP_DEC); display_strmap_hex("Protocol", gre.protocol, ethertype_map); } /* * Parse options fields. Note that if the C or the R bits are * present then both the checksum and offset fields are present */ if (C || R) { u_int16_t checksum; u_int16_t offset; /* * Nothing to report for minimal mode here, so just get * the checksum and offset and display them. */ if (get_packet_bytes((u_int8_t *) &checksum, pkt, 2) == 0) return; checksum = ntohs(checksum); if (!my_args->m) display("Checksum", (u_int8_t *) &checksum, 2, DISP_DEC); if (get_packet_bytes((u_int8_t *) &offset, pkt, 2) == 0) return; offset = ntohs(offset); if (!my_args->m) display("Offset", (u_int8_t *) &offset, 2, DISP_DEC); } /* Check for the K bit (key field) */ if (K) { u_int32_t key; if (get_packet_bytes((u_int8_t *) &key, pkt, 4) == 0) return; key = ntohl(key); if (!my_args->m) display("Key", (u_int8_t *) &key, 4, DISP_DEC); } /* Check for the sequence number field */ if (S) { u_int32_t seqno; if (get_packet_bytes((u_int8_t *) &seqno, pkt, 4) == 0) return; seqno = ntohl(seqno); if (!my_args->m) display("Sequence number", (u_int8_t *) &seqno, 4, DISP_DEC); } /* Check for routing field */ if (R) { u_int32_t routing; if (get_packet_bytes((u_int8_t *) &routing, pkt, 4) == 0) return; routing = ntohs(routing); if (!my_args->m) display("Routing", (u_int8_t *) &routing, 4, DISP_DEC); } } /* flush the hexbuffer */ hexbuffer_flush(); /* * Display the rest of the packet */ et = ethertype2func(protocol); if (et) { et(pkt); } } break; case 1: /* PPTP version */ { u_int8_t C, R, K, S, s, recur, A, flags, version; /* * Get the header */ if (get_packet_bytes((u_int8_t *) &gre1, pkt, sizeof(gre_v1_t)) == 0) return; /* * Conversions */ C = gre1.C_bit; R = gre1.R_bit; K = gre1.K_bit; S = gre1.S_bit; s = gre1.s_bit; recur = gre1.recur; A = gre1.A_bit; flags = gre1.flags; version = gre1.version; gre1.protocol = ntohs(gre1.protocol); gre1.payload_len = ntohs(gre1.payload_len); gre1.call_id = ntohs(gre1.call_id); /* * Dump header */ if (my_args->m) { display_minimal_string("| GREv1 "); } else { /* announcement */ display_header_banner("GREv1 Header"); /* fields */ display("Checksum (C) bit", &C, 1, DISP_BINNLZ); display("Routing (R) bit", &R, 1, DISP_BINNLZ); display("Key present (K) bit", &K, 1, DISP_BINNLZ); display("Seq. # present (S) bit", &S, 1, DISP_BINNLZ); display("Strict src rte (s) bit", &s, 1, DISP_BINNLZ); display("Recursion control", &recur, 1, DISP_DEC); display("Ack. # present (A) bit", &A, 1, DISP_BINNLZ); display("Flags", &flags, 1, DISP_DEC); display("Version", &version, 1, DISP_DEC); display_strmap_hex("Protocol", gre1.protocol, ethertype_map); display("Payload length", (u_int8_t *) &gre1.payload_len, 2, DISP_DEC); display("Call ID", (u_int8_t *) &gre1.call_id, 2, DISP_DEC); } /* * Check for sequence and acknowledgement number fields */ if (S) { u_int32_t seqno; if (get_packet_bytes((u_int8_t *) &seqno, pkt, 4) == 0) return; seqno = ntohl(seqno); if (my_args->m) { display_minimal_string("seq "); display_minimal((u_int8_t *) &seqno, 4, DISP_DEC); display_minimal_string(" "); } else display("Sequence number", (u_int8_t *) &seqno, 4, DISP_DEC); } if (A) { u_int32_t ackno; if (get_packet_bytes((u_int8_t *) &ackno, pkt, 4) == 0) return; ackno = ntohl(ackno); if (my_args->m) { display_minimal_string("ack "); display_minimal((u_int8_t *) &ackno, 4, DISP_DEC); display_minimal_string(" "); } else display("Acknowledgement number", (u_int8_t *) &ackno, 4, DISP_DEC); } /* dump the hex buffer */ hexbuffer_flush(); /* * Display the rest of the packet */ et = ethertype2func(gre1.protocol); if (et) { et(pkt); } else { /* * If we can't map the type, and we're in minimal mode, * dump the protocol type */ if (my_args->m) { display_minimal_string("("); display_minimal((u_int8_t *) &gre1.protocol, 2, DISP_HEX); display_minimal_string(") "); } } break; default: break; } } }